From ea38c0c1219bf8807947a6b68c3c7efc93ce18ff Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 28 Feb 2025 15:26:49 +0100 Subject: [PATCH] [CoreCLR] More CLR hosting support (#9572) Implements but does not complete CoreCLR host support. The runtime build will be enabled later, which will also be used to fix and update tests, potentially introducing new ones. This is in the interest to keep this PR as small as possible and getting the changes that affect the whole build system into `main` as quickly as possible. --- CLR-Host-Notes.md | 42 + Configuration.props | 11 + Xamarin.Android.sln | 2 +- .../Microsoft.Android.Runtime.proj | 2 +- .../installers/create-installers.targets | 16 +- .../scripts/generate-pinvoke-tables.sh | 93 +- .../scripts/xa_build_configuration.cmake.in | 5 + .../xaprepare/ConfigAndData/Configurables.cs | 23 +- .../xaprepare/Steps/Step_GenerateFiles.cs | 16 +- .../xaprepare/xaprepare/package-download.proj | 2 + src-ThirdParty/dotnet/runtime/README | 11 + src-ThirdParty/dotnet/runtime/coreclrhost.h | 158 +++ .../dotnet/runtime/host_runtime_contract.h | 63 + .../Mono.Android.Runtime.csproj | 1 + .../Android.Runtime/AndroidRuntimeInternal.cs | 52 +- src/Mono.Android/Android.Runtime/JNIEnv.cs | 31 +- .../Android.Runtime/JNIEnvInit.cs | 2 + .../Android.Runtime/RuntimeNativeMethods.cs | 8 +- src/Mono.Android/Java.Interop/TypeManager.cs | 34 +- .../targets/Microsoft.Android.Sdk.Aot.targets | 15 +- ...oft.Android.Sdk.AssemblyResolution.targets | 27 +- .../Microsoft.Android.Sdk.CoreCLR.targets | 13 + .../Tasks/CollectNativeFilesForArchive.cs | 5 +- .../CollectRuntimeConfigFilesForArchive.cs | 5 +- .../Tasks/GenerateJavaStubs.cs | 5 +- .../Tasks/GenerateMainAndroidManifest.cs | 34 +- .../Tasks/GeneratePackageManagerJava.cs | 76 +- .../Tasks/GetAotArguments.cs | 11 +- .../Tasks/LinkApplicationSharedLibraries.cs | 35 +- .../Tasks/ProcessAssemblies.cs | 15 +- .../Tasks/ProcessNativeLibraries.cs | 15 +- .../ProcessRuntimePackLibraryDirectories.cs | 101 ++ .../Tasks/WrapAssembliesAsSharedLibraries.cs | 5 +- .../Xamarin.Android.Build.Tests/BuildTest2.cs | 5 +- .../Utilities/DSOWrapperGenerator.cs | 18 +- .../Utilities/MonoAndroidHelper.cs | 32 +- .../Utilities/TypeMapGenerator.cs | 2 +- .../Xamarin.Android.Common.targets | 56 +- .../java/mono/android/MonoPackageManager.java | 3 +- src/native/.gitignore | 3 - src/native/CMakeLists.txt | 23 +- src/native/clr/host/CMakeLists.txt | 163 +++ src/native/clr/host/assembly-store.cc | 250 ++++ .../clr/host/generate-pinvoke-tables.cc | 753 ++++++++++++ src/native/clr/host/host-jni.cc | 60 + src/native/clr/host/host-util.cc | 19 + src/native/clr/host/host.cc | 393 +++++++ src/native/clr/host/internal-pinvokes.cc | 77 ++ src/native/clr/host/os-bridge.cc | 211 ++++ src/native/clr/host/pinvoke-override.cc | 105 ++ src/native/clr/host/pinvoke-tables.include | 1024 +++++++++++++++++ src/native/clr/host/typemap.cc | 319 +++++ src/native/clr/include/host/assembly-store.hh | 35 + src/native/clr/include/host/host-jni.hh | 48 + src/native/clr/include/host/host-util.hh | 11 + src/native/clr/include/host/host.hh | 68 ++ src/native/clr/include/host/os-bridge.hh | 58 + .../clr/include/host/pinvoke-override.hh | 223 ++++ src/native/clr/include/host/typemap.hh | 28 + .../include/runtime-base/internal-pinvokes.hh | 15 + .../include/runtime-base/timing-internal.hh | 7 +- src/native/clr/include/runtime-base/util.hh | 13 + src/native/clr/include/xamarin-app.hh | 33 +- .../clr/runtime-base/timing-internal.cc | 4 +- .../xamarin-app-stub/application_dso_stub.cc | 37 +- src/native/cmake/ArchiveDSOStub.cmake | 2 +- src/native/common/libstub/CMakeLists.txt | 2 +- src/native/native-clr.csproj | 27 + src/native/native.targets | 4 +- 69 files changed, 4829 insertions(+), 236 deletions(-) create mode 100644 CLR-Host-Notes.md create mode 100644 src-ThirdParty/dotnet/runtime/README create mode 100644 src-ThirdParty/dotnet/runtime/coreclrhost.h create mode 100644 src-ThirdParty/dotnet/runtime/host_runtime_contract.h create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/ProcessRuntimePackLibraryDirectories.cs delete mode 100644 src/native/.gitignore create mode 100644 src/native/clr/host/CMakeLists.txt create mode 100644 src/native/clr/host/assembly-store.cc create mode 100644 src/native/clr/host/generate-pinvoke-tables.cc create mode 100644 src/native/clr/host/host-jni.cc create mode 100644 src/native/clr/host/host-util.cc create mode 100644 src/native/clr/host/host.cc create mode 100644 src/native/clr/host/internal-pinvokes.cc create mode 100644 src/native/clr/host/os-bridge.cc create mode 100644 src/native/clr/host/pinvoke-override.cc create mode 100644 src/native/clr/host/pinvoke-tables.include create mode 100644 src/native/clr/host/typemap.cc create mode 100644 src/native/clr/include/host/assembly-store.hh create mode 100644 src/native/clr/include/host/host-jni.hh create mode 100644 src/native/clr/include/host/host-util.hh create mode 100644 src/native/clr/include/host/host.hh create mode 100644 src/native/clr/include/host/os-bridge.hh create mode 100644 src/native/clr/include/host/pinvoke-override.hh create mode 100644 src/native/clr/include/host/typemap.hh create mode 100644 src/native/clr/include/runtime-base/internal-pinvokes.hh create mode 100644 src/native/native-clr.csproj diff --git a/CLR-Host-Notes.md b/CLR-Host-Notes.md new file mode 100644 index 00000000000..325fa4e7e48 --- /dev/null +++ b/CLR-Host-Notes.md @@ -0,0 +1,42 @@ +# Notes + +## Potential optimizations + + * https://github.com/dotnet/runtime/blob/9b24fb60a19f62620ca1fc5e4eb2e3ae0b3b086d/src/coreclr/binder/assemblybindercommon.cpp#L844-L889 + * Managed C++ assemblies aren't available on Unix, no point in looking for them + * `candidates[]` is `WCHAR*`, while `ProbeAppBundle` takes UTF-8 - no point in doing the + conversion here + * Host contract + * It might make sense to pass strings as Unicode to host and back, to avoid conversions. + p/invoke names for instance, can be Unicode. So can be the assembly names. Native library + names should be UTF-8, but we can generate lookup tables for those at application build time + (e.g. indexed by an xxHash of the Unicode version of the name) - no conversion at run time. + * We need declarations of all he possible HRESULT errors (`S_OK` etc) + +## Stuff that should be changed + +### Logging +Currently, most of the messages logged by the runtime end up in `/dev/null` (either because they +are disabled in release build or because they log to stdio which doesn't work on Android). + +Logcat is the only way to get information from remote devices, especially via Google Play Console. + +We should log to logcat: + + + C++ exception messages + + abort() messages / fatal errors + + warnings + + errors + +A subsystem should be added which will provide a single function that will do actual output, implementation of which +will be specific to the platform. API should allow specification of severity, the actual message, and possibly a flag +to indicate whether the process should be aborted (the decision might also be based on the severity). Severity should +be shared between all targets, which then can (if needed) translate it to the target platform's value(s), if any. + +### Process termination +Runtime currently calls `abort()` in several places. This should probably become part of the host contract instead. +Being part of the contract, the target platform could implement process termination on `abort()` in a uniform way +(includes platform-specific logging, preparation etc) + +## Issues and workarounds + diff --git a/Configuration.props b/Configuration.props index 07a4740807e..2b4f189b5e5 100644 --- a/Configuration.props +++ b/Configuration.props @@ -220,4 +220,15 @@ + + diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index 782b20c69db..9eb3895b885 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -45,7 +45,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Diagnost EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Cecil", "external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil.csproj", "{D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "native", "src\native\native-mono.csproj", "{53EE4C57-1C03-405A-8243-8DA539546C88}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "native-mono", "src\native\native-mono.csproj", "{53EE4C57-1C03-405A-8243-8DA539546C88}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}" EndProject diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 6d1820cff7c..af99678ba05 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -60,7 +60,7 @@ projects that use the Microsoft.Android framework in .NET 6+. <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libunwind_xamarin.a" /> - + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so" /> <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so" /> diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index d7ed385f907..b7979948098 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -133,6 +133,10 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_net6.jar" ExcludeFromLegacy="true" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_net6.dex" ExcludeFromLegacy="true" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_net6.dex" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_clr.jar" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_clr.jar" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_clr.dex" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_clr.dex" ExcludeFromLegacy="true" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)manifestmerger.jar" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)proguard-android.txt" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)protobuf-net.dll" /> @@ -175,18 +179,6 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)K4os.Compression.LZ4.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ELFSharp.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ManifestOverlays\Timing.xml" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-arm64\libarchive-dso-stub.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-arm\libarchive-dso-stub.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-x64\libarchive-dso-stub.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-x86\libarchive-dso-stub.so" /> <_MSBuildTargetsSrcFiles Include="$(MSBuildTargetsSrcDir)\Xamarin.Android.AvailableItems.targets" /> diff --git a/build-tools/scripts/generate-pinvoke-tables.sh b/build-tools/scripts/generate-pinvoke-tables.sh index 2b0f8083e37..dbf70afd352 100755 --- a/build-tools/scripts/generate-pinvoke-tables.sh +++ b/build-tools/scripts/generate-pinvoke-tables.sh @@ -2,11 +2,14 @@ MY_DIR="$(dirname $0)" HOST="$(uname | tr A-Z a-z)" -NATIVE_DIR="${MY_DIR}/../../src/native/mono" -MONODROID_SOURCE_DIR="${NATIVE_DIR}/pinvoke-override" -GENERATOR_SOURCE="${MONODROID_SOURCE_DIR}/generate-pinvoke-tables.cc" -GENERATOR_BINARY="${MONODROID_SOURCE_DIR}/generate-pinvoke-tables" -TARGET_FILE="${MONODROID_SOURCE_DIR}/pinvoke-tables.include" +NATIVE_DIR="${MY_DIR}/../../src/native" +MONODROID_SOURCE_DIR="${NATIVE_DIR}/mono/pinvoke-override" +MONODROID_INCLUDE_DIR="${NATIVE_DIR}/mono/shared" +CLR_SOURCE_DIR="${NATIVE_DIR}/clr/host" +CLR_INCLUDE_DIR="${NATIVE_DIR}/clr/include/shared" +GENERATOR_SOURCE="generate-pinvoke-tables.cc" +GENERATOR_BINARY="generate-pinvoke-tables" +TARGET_FILE="pinvoke-tables.include" GENERATED_FILE="${TARGET_FILE}.generated" DIFF_FILE="${TARGET_FILE}.diff" EXTERNAL_DIR="${MY_DIR}/../../external/" @@ -64,33 +67,61 @@ case ${HOST} in *) die Unsupported OS ;; esac -${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 -I${NATIVE_DIR}/shared -I${NATIVE_DIR}/../common/include "${GENERATOR_SOURCE}" -o "${GENERATOR_BINARY}" -"${GENERATOR_BINARY}" "${GENERATED_FILE}" - -FILES_DIFFER="no" -cmp "${GENERATED_FILE}" "${TARGET_FILE}" > /dev/null 2>&1 || FILES_DIFFER="yes" - -RETVAL=0 -if [ "${TEST_ONLY}" == "no" ]; then - if [ "${FILES_DIFFER}" == "yes" ]; then - mv "${GENERATED_FILE}" "${TARGET_FILE}" - else - rm "${GENERATED_FILE}" - fi -else - if [ "${FILES_DIFFER}" == "yes" ]; then - echo "Generated p/invokes table file differs from the current one" - diff -U3 -Narp "${TARGET_FILE}" "${GENERATED_FILE}" > "${DIFF_FILE}" - - echo "Diff file saved in: ${DIFF_FILE}" - echo "------ DIFF START ------" - cat "${DIFF_FILE}" - echo "------ DIFF END ------" - echo - RETVAL=1 +function generate() +{ + local SOURCE_DIR="${1}" + local INCLUDE_DIR="${2}" + local SOURCE="${SOURCE_DIR}/${GENERATOR_SOURCE}" + local BINARY="${SOURCE_DIR}/${GENERATOR_BINARY}" + local RESULT="${SOURCE_DIR}/${GENERATED_FILE}" + local TARGET="${SOURCE_DIR}/${TARGET_FILE}" + local DIFF="${SOURCE_DIR}/${DIFF_FILE}" + + ${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 -I${INCLUDE_DIR} -I${NATIVE_DIR}/common/include "${SOURCE}" -o "${BINARY}" + "${BINARY}" "${RESULT}" + + FILES_DIFFER="no" + cmp "${RESULT}" "${TARGET}" > /dev/null 2>&1 || FILES_DIFFER="yes" + + if [ "${TEST_ONLY}" == "no" ]; then + if [ "${FILES_DIFFER}" == "yes" ]; then + mv "${RESULT}" "${TARGET}" + else + rm "${RESULT}" + fi else - echo Generated file is identical to the current one + if [ "${FILES_DIFFER}" == "yes" ]; then + echo "Generated p/invokes table file differs from the current one" + diff -U3 -Narp "${TARGET}" "${RESULT}" > "${DIFF}" + + echo "Diff file saved in: ${DIFF}" + echo "------ DIFF START ------" + cat "${DIFF}" + echo "------ DIFF END ------" + echo + RETVAL=1 + else + echo Generated file is identical to the current one + fi fi -fi +} + +RETVAL=0 +cat < GetCachedPath (ref openJDKInstallDir, () => Path.Combine (ctx.Properties.GetRequiredValue (KnownProperties.AndroidToolchainDirectory), Defaults.JdkFolder)); public static string OpenJDKCacheDir => GetCachedPath (ref openJDKCacheDir, () => ctx.Properties.GetRequiredValue (KnownProperties.AndroidToolchainCacheDirectory)); - // .NET 6 + // .NET 6+ public static string NetcoreAppRuntimeAndroidARM => GetCachedPath (ref netcoreAppRuntimeAndroidARM, () => GetNetcoreAppRuntimePath (ctx, "arm")); public static string NetcoreAppRuntimeAndroidARM64 => GetCachedPath (ref netcoreAppRuntimeAndroidARM64, () => GetNetcoreAppRuntimePath (ctx, "arm64")); public static string NetcoreAppRuntimeAndroidX86 => GetCachedPath (ref netcoreAppRuntimeAndroidX86, () => GetNetcoreAppRuntimePath (ctx, "x86")); public static string NetcoreAppRuntimeAndroidX86_64 => GetCachedPath (ref netcoreAppRuntimeAndroidX86_64, () => GetNetcoreAppRuntimePath (ctx, "x64")); + // CoreCLR + public static string CoreClrAppRuntimeAndroidARM => GetCachedPath (ref coreclrAppRuntimeAndroidARM, () => GetCoreClrAppRuntimePath (ctx, "arm")); + public static string CoreClrAppRuntimeAndroidARM64 => GetCachedPath (ref coreclrAppRuntimeAndroidARM64, () => GetCoreClrAppRuntimePath (ctx, "arm64")); + public static string CoreClrAppRuntimeAndroidX86 => GetCachedPath (ref coreclrAppRuntimeAndroidX86, () => GetCoreClrAppRuntimePath (ctx, "x86")); + public static string CoreClrAppRuntimeAndroidX86_64 => GetCachedPath (ref coreclrAppRuntimeAndroidX86_64, () => GetCoreClrAppRuntimePath (ctx, "x64")); + public static string MicrosoftNETWorkloadMonoPackageDir => Path.Combine ( XAPackagesDir, $"microsoft.net.workload.mono.toolchain.{{0}}.manifest-{ctx.Properties.GetRequiredValue (KnownProperties.DotNetMonoManifestVersionBand)}", @@ -242,6 +248,17 @@ static string GetNetcoreAppRuntimePath (Context ctx, string androidTarget) ); } + static string GetCoreClrAppRuntimePath (Context ctx, string androidTarget) + { + return Path.Combine ( + XAPackagesDir, + $"microsoft.netcore.app.runtime.android-{androidTarget}", + ctx.Properties.GetRequiredValue (KnownProperties.MicrosoftNETCoreAppRefPackageVersion), + "runtimes", + $"android-{androidTarget}" + ); + } + static string EnsureAndroidToolchainBinDirectories () { if (androidToolchainBinDirectory != null) @@ -278,6 +295,10 @@ static string GetCachedPath (ref string? variable, Func creator) static string? netcoreAppRuntimeAndroidARM64; static string? netcoreAppRuntimeAndroidX86; static string? netcoreAppRuntimeAndroidX86_64; + static string? coreclrAppRuntimeAndroidARM; + static string? coreclrAppRuntimeAndroidARM64; + static string? coreclrAppRuntimeAndroidX86; + static string? coreclrAppRuntimeAndroidX86_64; } } } diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs index af3c6cac1b6..65eddb2c042 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -98,6 +98,11 @@ GeneratedFile Get_Cmake_XA_Build_Configuration (Context context) { "@NETCORE_APP_RUNTIME_ANDROID_ARM64@", Utilities.EscapePathSeparators (Configurables.Paths.NetcoreAppRuntimeAndroidARM64) }, { "@NETCORE_APP_RUNTIME_ANDROID_X86@", Utilities.EscapePathSeparators (Configurables.Paths.NetcoreAppRuntimeAndroidX86) }, { "@NETCORE_APP_RUNTIME_ANDROID_X86_64@", Utilities.EscapePathSeparators (Configurables.Paths.NetcoreAppRuntimeAndroidX86_64) }, + + { "@CORECLR_APP_RUNTIME_ANDROID_ARM@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidARM) }, + { "@CORECLR_APP_RUNTIME_ANDROID_ARM64@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidARM64) }, + { "@CORECLR_APP_RUNTIME_ANDROID_X86@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidX86) }, + { "@CORECLR_APP_RUNTIME_ANDROID_X86_64@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidX86_64) }, }; return new GeneratedPlaceholdersFile ( @@ -107,7 +112,7 @@ GeneratedFile Get_Cmake_XA_Build_Configuration (Context context) ); } - GeneratedFile Get_Cmake_Presets (Context context) + GeneratedFile GetCmakePresetsCommon (Context context, string sourcesDir) { const string OutputFileName = "CMakePresets.json"; @@ -126,11 +131,16 @@ GeneratedFile Get_Cmake_Presets (Context context) return new GeneratedPlaceholdersFile ( replacements, - Path.Combine (Configurables.Paths.NativeSourcesDir, $"{OutputFileName}.in"), - Path.Combine (Configurables.Paths.NativeSourcesDir, OutputFileName) + Path.Combine (sourcesDir, $"{OutputFileName}.in"), + Path.Combine (sourcesDir, OutputFileName) ); } + GeneratedFile Get_Cmake_Presets (Context context) + { + return GetCmakePresetsCommon (context, Configurables.Paths.NativeSourcesDir); + } + GeneratedFile Get_Configuration_Generated_Props (Context context) { const string OutputFileName = "Configuration.Generated.props"; diff --git a/build-tools/xaprepare/xaprepare/package-download.proj b/build-tools/xaprepare/xaprepare/package-download.proj index f68692ad0b9..6f8053660df 100644 --- a/build-tools/xaprepare/xaprepare/package-download.proj +++ b/build-tools/xaprepare/xaprepare/package-download.proj @@ -20,6 +20,8 @@ Otherwise, $(MicrosoftNETCoreAppRefPackageVersion) from eng/Versions.props will + + diff --git a/src-ThirdParty/dotnet/runtime/README b/src-ThirdParty/dotnet/runtime/README new file mode 100644 index 00000000000..c84cccac88f --- /dev/null +++ b/src-ThirdParty/dotnet/runtime/README @@ -0,0 +1,11 @@ +The header files in this directory are verbatim copies taken from the +https://github.com/dotnet/runtime/ repository. + +They can be found in the following locations in the repository: + + src/native/corehost/host_runtime_contract.h + src/coreclr/hosts/inc/coreclrhost.h + +and they MUST be in sync with the current version of the runtime being +used. They don't have to come from the same version, but their content +must be ABI and API compatible with it. diff --git a/src-ThirdParty/dotnet/runtime/coreclrhost.h b/src-ThirdParty/dotnet/runtime/coreclrhost.h new file mode 100644 index 00000000000..12099870c97 --- /dev/null +++ b/src-ThirdParty/dotnet/runtime/coreclrhost.h @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// +// APIs for hosting CoreCLR +// + +#ifndef __CORECLR_HOST_H__ +#define __CORECLR_HOST_H__ + +#if defined(_WIN32) && defined(_M_IX86) +#define CORECLR_CALLING_CONVENTION __stdcall +#else +#define CORECLR_CALLING_CONVENTION +#endif + +#include + +#ifdef __cplusplus +#define CORECLR_HOSTING_API_LINKAGE extern "C" +#else +#define CORECLR_HOSTING_API_LINKAGE +#endif + +// For each hosting API, we define a function prototype and a function pointer +// The prototype is useful for implicit linking against the dynamic coreclr +// library and the pointer for explicit dynamic loading (dlopen, LoadLibrary) +#define CORECLR_HOSTING_API(function, ...) \ + CORECLR_HOSTING_API_LINKAGE int CORECLR_CALLING_CONVENTION function(__VA_ARGS__); \ + typedef int (CORECLR_CALLING_CONVENTION *function##_ptr)(__VA_ARGS__) + +// +// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain +// +// Parameters: +// exePath - Absolute path of the executable that invoked the ExecuteAssembly (the native host application) +// appDomainFriendlyName - Friendly name of the app domain that will be created to execute the assembly +// propertyCount - Number of properties (elements of the following two arguments) +// propertyKeys - Keys of properties of the app domain +// propertyValues - Values of properties of the app domain +// hostHandle - Output parameter, handle of the created host +// domainId - Output parameter, id of the created app domain +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_initialize, + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + +// +// Type of the callback function that can be set by the coreclr_set_error_writer +// +typedef void (*coreclr_error_writer_callback_fn) (const char *message); + +// +// Set callback for writing error logging +// +// Parameters: +// errorWriter - callback that will be called for each line of the error info +// - passing in NULL removes a callback that was previously set +// +// Returns: +// S_OK +// +CORECLR_HOSTING_API(coreclr_set_error_writer, + coreclr_error_writer_callback_fn errorWriter); + +// +// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_shutdown, + void* hostHandle, + unsigned int domainId); + +// +// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// latchedExitCode - Latched exit code after domain unloaded +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_shutdown_2, + void* hostHandle, + unsigned int domainId, + int* latchedExitCode); + +// +// Create a native callable function pointer for a managed method. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// entryPointAssemblyName - Name of the assembly which holds the custom entry point +// entryPointTypeName - Name of the type which holds the custom entry point +// entryPointMethodName - Name of the method which is the custom entry point +// delegate - Output parameter, the function stores a native callable function pointer to the delegate at the specified address +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_create_delegate, + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); + +// +// Execute a managed assembly with given arguments +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// argc - Number of arguments passed to the executed assembly +// argv - Array of arguments passed to the executed assembly +// managedAssemblyPath - Path of the managed assembly to execute (or NULL if using a custom entrypoint). +// exitCode - Exit code returned by the executed assembly +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_execute_assembly, + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); + +#undef CORECLR_HOSTING_API + +// +// Callback types used by the hosts +// +typedef bool(CORECLR_CALLING_CONVENTION ExternalAssemblyProbeFn)(const char* path, void** data_start, int64_t* size); +typedef bool(CORECLR_CALLING_CONVENTION BundleProbeFn)(const char* path, int64_t* offset, int64_t* size, int64_t* compressedSize); +typedef const void* (CORECLR_CALLING_CONVENTION PInvokeOverrideFn)(const char* libraryName, const char* entrypointName); + + +#endif // __CORECLR_HOST_H__ diff --git a/src-ThirdParty/dotnet/runtime/host_runtime_contract.h b/src-ThirdParty/dotnet/runtime/host_runtime_contract.h new file mode 100644 index 00000000000..9d03c52cf24 --- /dev/null +++ b/src-ThirdParty/dotnet/runtime/host_runtime_contract.h @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __HOST_RUNTIME_CONTRACT_H__ +#define __HOST_RUNTIME_CONTRACT_H__ + +#include +#include + +#if defined(_WIN32) + #define HOST_CONTRACT_CALLTYPE __stdcall +#else + #define HOST_CONTRACT_CALLTYPE +#endif + +// Known host property names +#define HOST_PROPERTY_RUNTIME_CONTRACT "HOST_RUNTIME_CONTRACT" +#define HOST_PROPERTY_APP_PATHS "APP_PATHS" +#define HOST_PROPERTY_BUNDLE_PROBE "BUNDLE_PROBE" +#define HOST_PROPERTY_ENTRY_ASSEMBLY_NAME "ENTRY_ASSEMBLY_NAME" +#define HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES "NATIVE_DLL_SEARCH_DIRECTORIES" +#define HOST_PROPERTY_PINVOKE_OVERRIDE "PINVOKE_OVERRIDE" +#define HOST_PROPERTY_PLATFORM_RESOURCE_ROOTS "PLATFORM_RESOURCE_ROOTS" +#define HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES "TRUSTED_PLATFORM_ASSEMBLIES" + +struct host_runtime_contract +{ + size_t size; + + // Context for the contract. Pass to functions taking a contract context. + void* context; + + // Get the value of a runtime property. + // Returns the length of the property including a terminating null or -1 if not found. + size_t(HOST_CONTRACT_CALLTYPE* get_runtime_property)( + const char* key, + /*out*/ char* value_buffer, + size_t value_buffer_size, + void* contract_context); + + // Probe an app bundle for `path`. Sets its location (`offset`, `size`) in the bundle if found. + // Returns true if found, false otherwise. If false, out parameter values are ignored by the runtime. + bool(HOST_CONTRACT_CALLTYPE* bundle_probe)( + const char* path, + /*out*/ int64_t* offset, + /*out*/ int64_t* size, + /*out*/ int64_t* compressedSize); + + // Get the function overriding the specified p/invoke (`library_name`, `entry_point_name`). + // Returns a pointer to the function if the p/invoke is overridden, nullptr otherwise. + const void* (HOST_CONTRACT_CALLTYPE* pinvoke_override)( + const char* library_name, + const char* entry_point_name); + + // Probe the host for `path`. Sets pointer to data start and its size, if found. + // Returns true if found, false otherwise. If false, out parameter values are ignored by the runtime. + bool(HOST_CONTRACT_CALLTYPE* external_assembly_probe)( + const char* path, + /*out*/ void **data_start, + /*out*/ int64_t* size); +}; + +#endif // __HOST_RUNTIME_CONTRACT_H__ diff --git a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj index 7612d7a2835..aac8b3bfe4c 100644 --- a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj +++ b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj @@ -52,6 +52,7 @@ + diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs b/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs index 141ff50f122..31d80445485 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs @@ -4,14 +4,64 @@ namespace Android.Runtime { + // The existence of InternalRuntimeTypeHolder and DotNetRuntimeTypeConverter classes looks weird, but + // we must handle a weird situation. AndroidRuntimeInternal needs to know in its static constructor + // what is the current runtime type, but it cannot query JNIEnvInit.RuntimeType, since that type lives + // in the Mono.Android assembly, while AndroidRuntimeInternal lives in Mono.Android.Runtime and it cannot + // access JNIEnvInit and Mono.Android.Runtime doesn't reference Mono.Android but Mono.Android **does** reference + // Mono.Android.Runtime and has access to its internals. + // + // Mono.Android.Runtime, also, includes several source files from Mono.Android - **both** assemblies + // include the same source files. In case of the DotNetRuntimeType enum, this declares two distinct types - one + // in Mono.Android and another in Mono.Android.Runtime, and so if JNIEnvInit.Initialize were to try to set the + // `DotNetRuntimeType RuntimeType;` field/property in either of the classes below, we'd get a compilation error + // to the effect of it being unable to cast `Android.Runtime.DotNetRuntimeType` to `Android.Runtime.DotNetRuntimeType`, + // which is usually as clear as mud :) + // + // To solve this and not duplicate code, the InternalRuntimeTypeHolder class is introduced which acts as a proxy since + // the AndroidRuntimeInternal static constructor must know the runtime type and JNIEnvInit.Initialize takes care of it by + // calling `SetRuntimeType` below long before AndroidRuntimeInternal cctor is invoked. + public static class InternalRuntimeTypeHolder + { + internal static DotNetRuntimeType RuntimeType = DotNetRuntimeType.Unknown; + + internal static void SetRuntimeType (uint runtimeType) + { + RuntimeType = DotNetRuntimeTypeConverter.Convert (runtimeType); + } + } + public static class AndroidRuntimeInternal { - internal static readonly Action mono_unhandled_exception = RuntimeNativeMethods.monodroid_debugger_unhandled_exception; + internal static readonly Action mono_unhandled_exception; #pragma warning disable CS0649 // Field is never assigned to. This field is assigned from monodroid-glue.cc. internal static volatile bool BridgeProcessing; // = false #pragma warning restore CS0649 // Field is never assigned to. + static AndroidRuntimeInternal () + { + mono_unhandled_exception = InternalRuntimeTypeHolder.RuntimeType switch { + DotNetRuntimeType.MonoVM => MonoUnhandledException, + DotNetRuntimeType.CoreCLR => CoreClrUnhandledException, + _ => throw new NotSupportedException ($"Internal error: runtime type {InternalRuntimeTypeHolder.RuntimeType} not supported") + }; + } + + static void CoreClrUnhandledException (Exception ex) + { + // TODO: Is this even needed on CoreCLR? + } + + // Needed when running under CoreCLR, which doesn't allow icalls/ecalls. Any method which contains any reference to + // an unregistered icall/ecall method will fail to JIT (even if the method isn't actually called). In this instance + // it affected the static constructor which tried to assign `RuntimeNativeMethods.monodroid_debugger_unhandled_exception` + // to `mono_unhandled_exception` at the top of the class. + static void MonoUnhandledException (Exception ex) + { + RuntimeNativeMethods.monodroid_debugger_unhandled_exception (ex); + } + public static void WaitForBridgeProcessing () { if (!BridgeProcessing) diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 01fb5c03572..abea8497918 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -77,6 +77,11 @@ internal static bool ShouldWrapJavaException (Java.Lang.Throwable? t, [CallerMem return wrap; } + static void MonoDroidUnhandledException (Exception ex) + { + RuntimeNativeMethods.monodroid_unhandled_exception (ex); + } + internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPtr, IntPtr javaExceptionPtr) { if (!JNIEnvInit.PropagateExceptions) @@ -95,7 +100,17 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt Logger.Log (LogLevel.Info, "MonoDroid", "UNHANDLED EXCEPTION:"); Logger.Log (LogLevel.Info, "MonoDroid", javaException.ToString ()); - RuntimeNativeMethods.monodroid_unhandled_exception (innerException ?? javaException); + switch (JNIEnvInit.RuntimeType) { + case DotNetRuntimeType.MonoVM: + MonoDroidUnhandledException (innerException ?? javaException); + break; + case DotNetRuntimeType.CoreCLR: + // TODO: what to do here? + break; + + default: + throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported"); + } } catch (Exception e) { Logger.Log (LogLevel.Error, "monodroid", "Exception thrown while raising AppDomain.UnhandledException event: " + e.ToString ()); } @@ -414,6 +429,14 @@ internal static void LogTypemapTrace (StackTrace st) } } + // We need this proxy method because if `TypeManagedToJava` contained the call to `monodroid_typemap_managed_to_java` + // (which is an icall, or ecall in CoreCLR parlance), CoreCLR JIT would throw an exception, refusing to compile the + // method. The exception would be thrown even if the icall weren't called (e.g. hidden behind a runtime type check) + static unsafe IntPtr monovm_typemap_managed_to_java (Type type, byte* mvidptr) + { + return monodroid_typemap_managed_to_java (type, mvidptr); + } + internal static unsafe string? TypemapManagedToJava (Type type) { if (mvid_bytes == null) @@ -430,7 +453,11 @@ internal static void LogTypemapTrace (StackTrace st) IntPtr ret; fixed (byte* mvidptr = mvid_data) { - ret = monodroid_typemap_managed_to_java (type, mvidptr); + ret = JNIEnvInit.RuntimeType switch { + DotNetRuntimeType.MonoVM => monovm_typemap_managed_to_java (type, mvidptr), + DotNetRuntimeType.CoreCLR => RuntimeNativeMethods.clr_typemap_managed_to_java (type.FullName, (IntPtr)mvidptr), + _ => throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported") + }; } if (ret == IntPtr.Zero) { diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs index 8c4ed9c5b7b..1e80e1f34b7 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs @@ -90,7 +90,9 @@ internal static void InitializeJniRuntime (JniRuntime runtime) [UnmanagedCallersOnly] internal static unsafe void Initialize (JnienvInitializeArgs* args) { + // This looks weird, see comments in RuntimeTypeInternal.cs RuntimeType = DotNetRuntimeTypeConverter.Convert (args->runtimeType); + InternalRuntimeTypeHolder.SetRuntimeType (args->runtimeType); IntPtr total_timing_sequence = IntPtr.Zero; IntPtr partial_timing_sequence = IntPtr.Zero; diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index 8c3edcf1045..0c0963c84f7 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -6,7 +6,7 @@ namespace Android.Runtime { - // Values must be identical to those in src/monodroid/jni/monodroid-glue-internal.hh + // NOTE: Keep this in sync with the native side in src/native/common/include/managed-interface.hh [Flags] enum TraceKind : uint { @@ -89,6 +89,12 @@ internal static class RuntimeNativeMethods [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_max_gref_get (); + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr clr_typemap_managed_to_java (string fullName, IntPtr mvid); + + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool clr_typemap_java_to_managed (string java_type_name, out IntPtr managed_assembly_name, out uint managed_type_token_id); + [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index f2e9a4bae7a..81ee5d6da47 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -224,9 +224,41 @@ static Exception CreateJavaLocationException () [MethodImplAttribute(MethodImplOptions.InternalCall)] static extern Type monodroid_typemap_java_to_managed (string java_type_name); + static Type monovm_typemap_java_to_managed (string java_type_name) + { + return monodroid_typemap_java_to_managed (java_type_name); + } + + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Value of java_type_name isn't statically known.")] + static Type? clr_typemap_java_to_managed (string java_type_name) + { + bool result = RuntimeNativeMethods.clr_typemap_java_to_managed (java_type_name, out IntPtr managedAssemblyNamePointer, out uint managedTypeTokenId); + if (!result || managedAssemblyNamePointer == IntPtr.Zero) { + return null; + } + + string managedAssemblyName = Marshal.PtrToStringAnsi (managedAssemblyNamePointer); + Assembly assembly = Assembly.Load (managedAssemblyName); + Type? ret = null; + foreach (Module module in assembly.Modules) { + ret = module.ResolveType ((int)managedTypeTokenId); + if (ret != null) { + break; + } + } + + Logger.Log (LogLevel.Info, "monodroid", $"Loaded type: {ret}"); + return ret; + } + internal static Type? GetJavaToManagedType (string class_name) { - Type? type = monodroid_typemap_java_to_managed (class_name); + Type? type = JNIEnvInit.RuntimeType switch { + DotNetRuntimeType.MonoVM => monovm_typemap_java_to_managed (class_name), + DotNetRuntimeType.CoreCLR => clr_typemap_java_to_managed (class_name), + _ => throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported") + }; + if (type != null) return type; diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 1ae80b94409..17d7009cc86 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -30,6 +30,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). + @@ -77,6 +78,17 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). + + + + + + + + ZipAlignmentPages="$(AndroidZipAlignment)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index afda07d8c7d..54da968c370 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets @@ -12,6 +12,7 @@ _ResolveAssemblies MSBuild target. + @@ -105,6 +106,7 @@ _ResolveAssemblies MSBuild target. <_ProjectToBuild Include="$(MSBuildProjectFile)" AdditionalProperties="RuntimeIdentifier=%(_RIDs.Identity);$(_AdditionalProperties)" /> + + + + + + + + + + + + <_InnerIntermediateOutputPath Condition=" '$(RuntimeIdentifier)' == '' ">$(IntermediateOutputPath)%(_RIDs.Identity)\ @@ -125,10 +143,6 @@ _ResolveAssemblies MSBuild target. <_ResolvedJavaLibraries Include="@(ResolvedFileToPublish)" Condition=" '%(ResolvedFileToPublish.Extension)' == '.jar' " /> - - - - <_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'MonoVM' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'MonoVM' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.release" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.release" /> + CoreCLR + + + <_DotNetRuntimeRepo>$(_CLRLocalRuntimePath) + <_DotNetRuntimeConfiguration Condition=" '$(_DotNetRuntimeConfiguration)' == '' ">Release + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs index 78b64397882..4cf23bd43e3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs @@ -53,6 +53,9 @@ public class CollectNativeFilesForArchive : AndroidTask [Required] public string AndroidBinUtilsDirectory { get; set; } = ""; + [Required] + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); + [Required] public string IntermediateOutputPath { get; set; } = ""; @@ -68,7 +71,7 @@ public class CollectNativeFilesForArchive : AndroidTask public override bool RunTask () { var apk = new PackageFileListBuilder (); - var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, IntermediateOutputPath); + var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, RuntimePackLibraryDirectories, IntermediateOutputPath); var outputFiles = new List { ApkOutputPath diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs index 1aa86a4c907..2be75d0bb99 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs @@ -19,6 +19,9 @@ public class CollectRuntimeConfigFilesForArchive : AndroidTask [Required] public string AndroidBinUtilsDirectory { get; set; } = ""; + [Required] + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); + [Required] public string IntermediateOutputPath { get; set; } = ""; @@ -33,7 +36,7 @@ public class CollectRuntimeConfigFilesForArchive : AndroidTask public override bool RunTask () { var files = new PackageFileListBuilder (); - var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, IntermediateOutputPath); + var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, RuntimePackLibraryDirectories, IntermediateOutputPath); // We will place rc.bin in the `lib` directory next to the blob, to make startup slightly faster, as we will find the config file right after we encounter // our assembly store. Not only that, but also we'll be able to skip scanning the `base.apk` archive when split configs are enabled (which they are in 99% diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 806bb19a3fd..5beba41c2cc 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -317,10 +317,7 @@ void WriteTypeMappings (NativeCodeGenState state) // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep` return; } - if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { - // TODO: CoreCLR typemaps will be emitted later - return; - } + Log.LogDebugMessage ($"Generating type maps for architecture '{state.TargetArch}'"); var tmg = new TypeMapGenerator (Log, state, androidRuntime); if (!tmg.Generate (Debug, SkipJniAddNativeMethodRegistrationAttributeScan, TypemapOutputDirectory, GenerateNativeAssembly)) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs index 9603655aaf2..9e8f3e9ea94 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs @@ -136,23 +136,23 @@ IList MergeManifest (NativeCodeGenState codeGenState, Dictionary additionalProviders) { - if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { - // Create additional runtime provider java sources. - bool isMonoVM = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM; - string providerTemplateFile = isMonoVM ? - "MonoRuntimeProvider.Bundled.java" : - "NativeAotRuntimeProvider.java"; - string providerTemplate = GetResource (providerTemplateFile); - - foreach (var provider in additionalProviders) { - var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); - var real_provider = isMonoVM ? - Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : - Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); - Files.CopyIfStringChanged (contents, real_provider); - } - } else { - Log.LogDebugMessage ($"Skipping android.content.ContentProvider generation for: {androidRuntime}"); + // Create additional runtime provider java sources. + bool isMonoVM = androidRuntime switch { + Xamarin.Android.Tasks.AndroidRuntime.MonoVM => true, + Xamarin.Android.Tasks.AndroidRuntime.CoreCLR => true, + _ => false, + }; + string providerTemplateFile = isMonoVM ? + "MonoRuntimeProvider.Bundled.java" : + "NativeAotRuntimeProvider.java"; + string providerTemplate = GetResource (providerTemplateFile); + + foreach (var provider in additionalProviders) { + var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); + var real_provider = isMonoVM ? + Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : + Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); + Files.CopyIfStringChanged (contents, real_provider); } // For NativeAOT, generate JavaInteropRuntime.java diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index d58e7f70e79..d3f039d6642 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -64,8 +64,12 @@ public class GeneratePackageManagerJava : AndroidTask [Required] public bool EnablePreloadAssembliesDefault { get; set; } + [Required] + public bool TargetsCLR { get; set; } + public bool EnableMarshalMethods { get; set; } public string RuntimeConfigBinFilePath { get; set; } + public string ProjectRuntimeConfigFilePath { get; set; } = String.Empty; public string BoundExceptionType { get; set; } public string PackageNamingPolicy { get; set; } @@ -319,31 +323,53 @@ void AddEnvironment () bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); - var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { - UsesMonoAOT = usesMonoAOT, - UsesMonoLLVM = EnableLLVM, - UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, - MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), - AotEnableLazyLoad = AndroidAotEnableLazyLoad, - AndroidPackageName = AndroidPackageName, - BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, - PackageNamingPolicy = pnp, - BoundExceptionType = boundExceptionType, - JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, - HaveRuntimeConfigBlob = haveRuntimeConfigBlob, - NumberOfAssembliesInApk = assemblyCount, - BundledAssemblyNameWidth = assemblyNameWidth, - MonoComponents = (MonoComponent)monoComponents, - NativeLibraries = uniqueNativeLibraries, - HaveAssemblyStore = UseAssemblyStore, - AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, - JNIEnvInitializeToken = jnienv_initialize_method_token, - JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, - JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, - JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, - MarshalMethodsEnabled = EnableMarshalMethods, - IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), - }; + LLVMIR.LlvmIrComposer appConfigAsmGen; + + if (TargetsCLR) { + Dictionary? runtimeProperties = RuntimePropertiesParser.ParseConfig (ProjectRuntimeConfigFilePath); + appConfigAsmGen = new ApplicationConfigNativeAssemblyGeneratorCLR (environmentVariables, systemProperties, runtimeProperties, Log) { + UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, + AndroidPackageName = AndroidPackageName, + PackageNamingPolicy = pnp, + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + NumberOfAssembliesInApk = assemblyCount, + BundledAssemblyNameWidth = assemblyNameWidth, + NativeLibraries = uniqueNativeLibraries, + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, + JNIEnvInitializeToken = jnienv_initialize_method_token, + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, + MarshalMethodsEnabled = EnableMarshalMethods, + IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + }; + } else { + appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { + UsesMonoAOT = usesMonoAOT, + UsesMonoLLVM = EnableLLVM, + UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, + MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), + AotEnableLazyLoad = AndroidAotEnableLazyLoad, + AndroidPackageName = AndroidPackageName, + BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, + PackageNamingPolicy = pnp, + BoundExceptionType = boundExceptionType, + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + HaveRuntimeConfigBlob = haveRuntimeConfigBlob, + NumberOfAssembliesInApk = assemblyCount, + BundledAssemblyNameWidth = assemblyNameWidth, + MonoComponents = (MonoComponent)monoComponents, + NativeLibraries = uniqueNativeLibraries, + HaveAssemblyStore = UseAssemblyStore, + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, + JNIEnvInitializeToken = jnienv_initialize_method_token, + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, + MarshalMethodsEnabled = EnableMarshalMethods, + IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + }; + } LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct (); foreach (string abi in SupportedAbis) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs index 749c1df612f..fce21988f58 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs @@ -32,6 +32,9 @@ public abstract class GetAotArguments : AsyncTask [Required] public string TargetName { get; set; } = ""; + [Required] + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); + /// /// Will be blank in .NET 6+ /// @@ -295,10 +298,12 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP libs.Add (Path.Combine (androidLibPath, "libc.so")); libs.Add (Path.Combine (androidLibPath, "libm.so")); } else if (!UseAndroidNdk && EnableLLVM) { - string libstubsPath = MonoAndroidHelper.GetLibstubsArchDirectoryPath (AndroidBinUtilsDirectory, arch); + string? libstubsPath = MonoAndroidHelper.GetRuntimePackNativeLibDir (arch, RuntimePackLibraryDirectories); - libs.Add (Path.Combine (libstubsPath, "libc.so")); - libs.Add (Path.Combine (libstubsPath, "libm.so")); + if (!String.IsNullOrEmpty (libstubsPath)) { + libs.Add (Path.Combine (libstubsPath, "libc.so")); + libs.Add (Path.Combine (libstubsPath, "libm.so")); + } } if (libs.Count > 0) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 6fb2dac8967..5ac7faebc82 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -43,6 +43,12 @@ sealed class InputFiles [Required] public string AndroidBinUtilsDirectory { get; set; } + [Required] + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); + + [Required] + public bool TargetsCLR { get; set; } + public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment64Bit; public override System.Threading.Tasks.Task RunTaskAsync () @@ -114,20 +120,19 @@ void RunLinker (Config config) IEnumerable GetLinkerConfigs () { - string runtimeNativeLibsDir = MonoAndroidHelper.GetNativeLibsRootDirectoryPath (AndroidBinUtilsDirectory); - string runtimeNativeLibStubsDir = MonoAndroidHelper.GetLibstubsRootDirectoryPath (AndroidBinUtilsDirectory); var abis = new Dictionary (StringComparer.Ordinal); ITaskItem[] dsos = ApplicationSharedLibraries; foreach (ITaskItem item in dsos) { string abi = item.GetMetadata ("abi"); - abis [abi] = GatherFilesForABI (item.ItemSpec, abi, ObjectFiles, runtimeNativeLibsDir, runtimeNativeLibStubsDir); + abis [abi] = GatherFilesForABI (item.ItemSpec, abi, ObjectFiles); } - const string commonLinkerArgs = + string soname = TargetsCLR ? "libxamarin-app-clr.so" : "libxamarin-app.so"; + string commonLinkerArgs = "--shared " + "--allow-shlib-undefined " + "--export-dynamic " + - "-soname libxamarin-app.so " + + $"-soname {soname} " + "-z relro " + "-z noexecstack " + "--enable-new-dtags " + @@ -203,19 +208,21 @@ IEnumerable GetLinkerConfigs () } } - InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem[] objectFiles, string runtimeNativeLibsDir, string runtimeNativeLibStubsDir) + InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem[] objectFiles) { - List extraLibraries = null; + AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi); + var libDirs = new HashSet (StringComparer.OrdinalIgnoreCase) { + MonoAndroidHelper.GetRuntimePackNativeLibDir (arch, RuntimePackLibraryDirectories), + }; + string RID = MonoAndroidHelper.AbiToRid (abi); AndroidTargetArch targetArch = MonoAndroidHelper.AbiToTargetArch (abi); - string libStubsPath = Path.Combine (runtimeNativeLibStubsDir, RID); - string runtimeLibsDir = Path.Combine (runtimeNativeLibsDir, RID); - extraLibraries = new List { - $"-L \"{runtimeLibsDir}\"", - $"-L \"{libStubsPath}\"", - "-lc", - }; + var extraLibraries = new List (); + foreach (string dir in libDirs) { + extraLibraries.Add ($"-L \"{dir}\""); + } + extraLibraries.Add ("-lc"); return new InputFiles { OutputSharedLibrary = runtimeSharedLibrary, diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs index bce699d3883..884a94519e6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs @@ -36,6 +36,9 @@ public class ProcessAssemblies : AndroidTask public ITaskItem [] InputJavaLibraries { get; set; } = Array.Empty (); + public string AndroidRuntime { get; set; } = String.Empty; + public string LocalClrDirectory { get; set; } = String.Empty; + [Output] public ITaskItem []? OutputAssemblies { get; set; } @@ -100,7 +103,8 @@ public override bool RunTask () void SetAssemblyAbiMetadata (string abi, ITaskItem assembly, ITaskItem? symbol) { if (String.IsNullOrEmpty (abi)) { - throw new ArgumentException ("must not be null or empty", nameof (abi)); + string rid = assembly.GetMetadata ("RuntimeIdentifier") ?? "unknown"; + throw new ArgumentException ($"must not be null or empty for assembly item '{assembly}' (RID '{rid}')", nameof (abi)); } assembly.SetMetadata ("Abi", abi); @@ -110,6 +114,13 @@ void SetAssemblyAbiMetadata (string abi, ITaskItem assembly, ITaskItem? symbol) void SetAssemblyAbiMetadata (ITaskItem assembly, ITaskItem? symbol) { string rid = assembly.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (rid)) { + throw new InvalidOperationException ($"Assembly '{assembly}' item doesn't have the required RuntimeIdentifier metadata"); + } + + if (!MonoAndroidHelper.IsValidRID (rid)) { + throw new InvalidOperationException ($"Assembly '{assembly}' item targets unsupported RuntimeIdentifier '{rid}'"); + } SetAssemblyAbiMetadata (AndroidRidAbiHelper.RuntimeIdentifierToAbi (rid), assembly, symbol); } @@ -165,7 +176,7 @@ void SetDestinationSubDirectory (ITaskItem assembly, ITaskItem? symbol) { string? rid = assembly.GetMetadata ("RuntimeIdentifier"); if (String.IsNullOrEmpty (rid)) { - throw new InvalidOperationException ($"Assembly '{assembly}' item is missing required "); + throw new InvalidOperationException ($"Assembly '{assembly}' item is missing required RuntimeIdentifier data"); } string? abi = AndroidRidAbiHelper.RuntimeIdentifierToAbi (rid); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs index 4970875d659..d0c1263bc29 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs @@ -59,11 +59,16 @@ public override bool RunTask () } continue; } - // Both libmono-android.debug.so and libmono-android.release.so are in InputLibraries. + // Both lib{mono,net}-android.debug.so and lib{mono,net}-android.release.so are in InputLibraries. // Use IncludeDebugSymbols to determine which one to include. - // We may eventually have files such as `libmono-android-checked+asan.release.so` as well. + // We may eventually have files such as `lib{mono,net}-android-checked+asan.release.so` as well. var fileName = Path.GetFileNameWithoutExtension (library.ItemSpec); - if (fileName.StartsWith ("libmono-android", StringComparison.Ordinal)) { + if (ExcludedLibraries != null && ExcludedLibraries.Contains (fileName, StringComparer.OrdinalIgnoreCase)) { + Log.LogDebugMessage ($"Excluding '{library.ItemSpec}'"); + continue; + } + + if (fileName.StartsWith ("libmono-android", StringComparison.Ordinal) || fileName.StartsWith ("libnet-android", StringComparison.Ordinal)) { if (fileName.EndsWith (".debug", StringComparison.Ordinal)) { if (!IncludeDebugSymbols) continue; @@ -73,6 +78,7 @@ public override bool RunTask () continue; library.SetMetadata ("ArchiveFileName", "libmonodroid.so"); } + Log.LogDebugMessage ($"Including runtime: {library}"); } else if (DebugNativeLibraries.Contains (fileName)) { if (!IncludeDebugSymbols) { Log.LogDebugMessage ($"Excluding '{library.ItemSpec}' for release builds."); @@ -82,9 +88,6 @@ public override bool RunTask () if (!wantedComponents.Contains (fileName)) { continue; } - } else if (ExcludedLibraries != null && ExcludedLibraries.Contains (fileName, StringComparer.OrdinalIgnoreCase)) { - Log.LogDebugMessage ($"Excluding '{library.ItemSpec}'"); - continue; } output.Add (library); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessRuntimePackLibraryDirectories.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessRuntimePackLibraryDirectories.cs new file mode 100644 index 00000000000..04c1369c345 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessRuntimePackLibraryDirectories.cs @@ -0,0 +1,101 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; + +using Microsoft.Build.Utilities; +using Microsoft.Build.Framework; +using Microsoft.Android.Build.Tasks; + +namespace Xamarin.Android.Tasks; + +public class ProcessRuntimePackLibraryDirectories : AndroidTask +{ + public override string TaskPrefix => "FRPLD"; + + static readonly HashSet NativeLibraryNames = new (StringComparer.OrdinalIgnoreCase) { + "libarchive-dso-stub.so", + "libc.so", + "libdl.so", + "liblog.so", + "libm.so", + "libz.so", + }; + + [Required] + public ITaskItem[] ResolvedFilesToPublish { get; set; } = Array.Empty (); + + [Output] + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); + + [Output] + public ITaskItem[] NativeLibrariesToRemove { get; set; } = Array.Empty (); + + public override bool RunTask () + { + var libDirs = new List (); + var librariesToRemove = new List (); + var seenRIDs = new HashSet (StringComparer.OrdinalIgnoreCase); + + foreach (ITaskItem item in ResolvedFilesToPublish) { + if (!IsInSupportedRuntimePack (item)) { + continue; + } + + string? fileName = Path.GetFileName (item.ItemSpec); + if (String.IsNullOrEmpty (fileName) || !NativeLibraryNames.Contains (fileName)) { + continue; + } + + string? rid = item.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (rid)) { + Log.LogDebugMessage ($"Ignoring item '{item}' because it contains no runtime identifier metadata"); + continue; + } + + if (!seenRIDs.Contains (rid)) { + string? dirName = Path.GetDirectoryName (item.ItemSpec); + if (String.IsNullOrEmpty (dirName)) { + Log.LogDebugMessage ($"Item '{item}' path doesn't contain full file path"); + } else { + libDirs.Add (MakeLibDirItem (item, dirName)); + } + seenRIDs.Add (rid); + Log.LogDebugMessage ($"Discovered runtime pack library directory for '{rid}': {dirName}"); + } + + librariesToRemove.Add (item); + Log.LogDebugMessage ($"Item '{item}' will be removed from the set of native libraries to publish"); + } + + RuntimePackLibraryDirectories = libDirs.ToArray (); + NativeLibrariesToRemove = librariesToRemove.ToArray (); + + return !Log.HasLoggedErrors; + } + + ITaskItem MakeLibDirItem (ITaskItem sourceItem, string dir) + { + var ret = new TaskItem (dir); + sourceItem.CopyMetadataTo (ret); + + // These make no sense for directories, remove just to be safe + ret.RemoveMetadata ("CopyLocal"); + ret.RemoveMetadata ("CopyToPublishDirectory"); + ret.RemoveMetadata ("DestinationSubPath"); + ret.RemoveMetadata ("RelativePath"); + return ret; + } + + bool IsInSupportedRuntimePack (ITaskItem item) + { + string? NuGetPackageId = item.GetMetadata ("NuGetPackageId"); + if (String.IsNullOrEmpty (NuGetPackageId)) { + return false; + } + + return NuGetPackageId.StartsWith ("Microsoft.Android.Runtime.CoreCLR.", StringComparison.OrdinalIgnoreCase) || + NuGetPackageId.StartsWith ("Microsoft.Android.Runtime.Mono.", StringComparison.OrdinalIgnoreCase); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs index ab297dd6d29..4a83aa4266e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs @@ -24,6 +24,9 @@ public class WrapAssembliesAsSharedLibraries : AndroidTask [Required] public string AndroidBinUtilsDirectory { get; set; } = ""; + [Required] + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); + public bool IncludeDebugSymbols { get; set; } [Required] @@ -42,7 +45,7 @@ public class WrapAssembliesAsSharedLibraries : AndroidTask public override bool RunTask () { - var wrapper_config = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, IntermediateOutputPath); + var wrapper_config = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, RuntimePackLibraryDirectories, IntermediateOutputPath); var files = new PackageFileListBuilder (); if (UseAssemblyStore) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 362ab093137..3d10afa3e33 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -108,6 +108,9 @@ public void BuildBasicApplication ([Values (true, false)] bool isRelease, [Value [Test] public void BasicApplicationOtherRuntime ([Values (true, false)] bool isRelease) { + // This test would fail, as it requires **our** updated runtime pack, which isn't currently created + // It is created in `src/native/native-clr.csproj` which isn't built atm. + Assert.Ignore ("CoreCLR support isn't fully enabled yet. This test will be enabled in a follow-up PR."); var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, // Add locally downloaded CoreCLR packs @@ -465,7 +468,7 @@ public void XA1037PropertyDeprecatedWarning (string property, string value, bool XamarinAndroidProject proj = isBindingProject ? new XamarinAndroidBindingProject () : new XamarinAndroidApplicationProject (); proj.IsRelease = isRelease; proj.SetProperty (property, value); - + using (ProjectBuilder b = isBindingProject ? CreateDllBuilder (Path.Combine ("temp", TestName)) : CreateApkBuilder (Path.Combine ("temp", TestName))) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); Assert.IsTrue (StringAssertEx.ContainsText (b.LastBuildOutput, $"The '{property}' MSBuild property is deprecated and will be removed"), diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs index 15801bf3dd3..3dd7b1863cb 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs @@ -34,6 +34,8 @@ class DSOWrapperGenerator { internal const string RegisteredConfigKey = ".:!DSOWrapperGeneratorConfig!:."; + public const string StubFileName = "libarchive-dso-stub.so"; + internal class Config { public Dictionary DSOStubPaths { get; } @@ -53,24 +55,22 @@ public Config (Dictionary stubPaths, string androidBi // const ulong PayloadSectionAlignment = 0x4000; - public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDirectory, string baseOutputDirectory) + public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDirectory, ITaskItem[] runtimePackLibraryDirs, string baseOutputDirectory) { var stubPaths = new Dictionary (); - string archiveDSOStubsRootDir = MonoAndroidHelper.GetDSOStubsRootDirectoryPath (androidBinUtilsDirectory); - foreach (string dir in Directory.EnumerateDirectories (archiveDSOStubsRootDir, "android-*")) { - string rid = Path.GetFileName (dir); - AndroidTargetArch arch = MonoAndroidHelper.RidToArchMaybe (rid); - if (arch == AndroidTargetArch.None) { - log.LogDebugMessage ($"Unable to extract a supported RID name from directory path '{dir}'"); + foreach (ITaskItem packLibDir in runtimePackLibraryDirs) { + string ?packRID = packLibDir.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (packRID)) { continue; } - string stubPath = Path.Combine (dir, "libarchive-dso-stub.so"); + string stubPath = Path.Combine (packLibDir.ItemSpec, StubFileName); if (!File.Exists (stubPath)) { - throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubPath}' does not exist"); + throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubPath}' does not exist in runtime pack at {packLibDir}"); } + AndroidTargetArch arch = MonoAndroidHelper.RidToArch (packRID); stubPaths.Add (arch, stubPath); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index f50e1444750..bd5f567cae6 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -569,28 +569,24 @@ static string GetToolsRootDirectoryRelativePath (string androidBinUtilsDirectory return relPath; } - public static string GetLibstubsArchDirectoryPath (string androidBinUtilsDirectory, AndroidTargetArch arch) - { - return Path.Combine (GetLibstubsRootDirectoryPath (androidBinUtilsDirectory), ArchToRid (arch)); - } - - public static string GetLibstubsRootDirectoryPath (string androidBinUtilsDirectory) +#if MSBUILD + public static string? GetRuntimePackNativeLibDir (AndroidTargetArch arch, IEnumerable runtimePackLibDirs) { - string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory); - return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "libstubs")); - } + foreach (ITaskItem item in runtimePackLibDirs) { + string? rid = item.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (rid)) { + continue; + } - public static string GetDSOStubsRootDirectoryPath (string androidBinUtilsDirectory) - { - string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory); - return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "dsostubs")); - } + AndroidTargetArch itemArch = RidToArch (rid); + if (itemArch == arch) { + return item.ItemSpec; + } + } - public static string GetNativeLibsRootDirectoryPath (string androidBinUtilsDirectory) - { - string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory); - return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "lib")); + return null; } +#endif // MSBUILD public static string? GetAssemblyCulture (ITaskItem assembly) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs index 32ee751b0c2..7a39539e258 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs @@ -448,7 +448,7 @@ bool GenerateRelease (bool skipJniAddNativeMethodRegistrationAttributeScan, stri LLVMIR.LlvmIrComposer composer = runtime switch { AndroidRuntime.MonoVM => new TypeMappingReleaseNativeAssemblyGenerator (log, new NativeTypeMappingData (log, modules)), - AndroidRuntime.CoreCLR => throw new NotImplementedException ("CoreCLR support not implemented yet"), + AndroidRuntime.CoreCLR => new TypeMappingReleaseNativeAssemblyGeneratorCLR (log, new NativeTypeMappingData (log, modules)), _ => throw new NotSupportedException ($"Internal error: unsupported runtime {runtime}") }; diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 5061e088da5..d37b47e7c6f 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -305,6 +305,8 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' And '$(EmbedAssembliesIntoApk)' == 'False' ">True <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' ">False + <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' == 'CoreCLR' ">True + <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' != 'CoreCLR' ">False @@ -339,6 +341,10 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. True False + + + False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods) @@ -1364,10 +1370,15 @@ because xbuild doesn't support framework reference assemblies. - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_net6.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_net6.dex + + + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_clr.jar + <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_clr.dex + @@ -1388,7 +1399,7 @@ because xbuild doesn't support framework reference assemblies. DependsOnTargets="_CollectRuntimeJarFilenames;$(_BeforeAddStaticResources);_GetMonoPlatformJarPath"> @@ -1463,7 +1474,7 @@ because xbuild doesn't support framework reference assemblies. - + @@ -1800,6 +1811,8 @@ because xbuild doesn't support framework reference assemblies. UseAssemblyStore="$(AndroidUseAssemblyStore)" EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" + TargetsCLR="$(_AndroidUseCLR)" + ProjectRuntimeConfigFilePath="$(ProjectRuntimeConfigFilePath)" > @@ -1985,7 +1998,7 @@ because xbuild doesn't support framework reference assemblies. @@ -2061,7 +2074,7 @@ because xbuild doesn't support framework reference assemblies. - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app.so"> %(_BuildTargetAbis.Identity) @@ -2079,6 +2092,8 @@ because xbuild doesn't support framework reference assemblies. DebugBuild="$(AndroidIncludeDebugSymbols)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" ZipAlignmentPages="$(AndroidZipAlignment)" + TargetsCLR="$(_AndroidUseCLR)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)" /> @@ -2181,7 +2196,7 @@ because xbuild doesn't support framework reference assemblies. <_ApkOutputPath>$(_BaseZipIntermediate) - + - + + UseAssemblyStore="$(AndroidUseAssemblyStore)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> @@ -2224,11 +2242,14 @@ because xbuild doesn't support framework reference assemblies. + + SupportedAbis="@(_BuildTargetAbis)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> @@ -2245,7 +2266,8 @@ because xbuild doesn't support framework reference assemblies. CheckedBuild="$(_AndroidCheckedBuild)" ZipAlignmentPages="$(AndroidZipAlignment)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - IntermediateOutputPath="$(IntermediateOutputPath)"> + IntermediateOutputPath="$(IntermediateOutputPath)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> @@ -2265,7 +2287,7 @@ because xbuild doesn't support framework reference assemblies. - + - + + + SupportedAbis="@(_BuildTargetAbis)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> @@ -2363,7 +2388,8 @@ because xbuild doesn't support framework reference assemblies. IncludeWrapSh="$(AndroidIncludeWrapSh)" CheckedBuild="$(_AndroidCheckedBuild)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - IntermediateOutputPath="$(IntermediateOutputPath)"> + IntermediateOutputPath="$(IntermediateOutputPath)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> diff --git a/src/java-runtime/java/mono/android/MonoPackageManager.java b/src/java-runtime/java/mono/android/MonoPackageManager.java index 1c0487e046f..db90e2092ef 100644 --- a/src/java-runtime/java/mono/android/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/MonoPackageManager.java @@ -65,7 +65,8 @@ public static void LoadApplication (Context context) } // - // Should the order change here, src/monodroid/jni/SharedConstants.hh must be updated accordingly + // Should the order change here, src/mono/native/runtime-base/shared-constants.hh and + // src/native/clr/include/constants.hh must be updated accordingly // String[] appDirs = new String[] {filesDir, cacheDir, dataDir}; boolean haveSplitApks = runtimePackage.splitSourceDirs != null && runtimePackage.splitSourceDirs.length > 0; diff --git a/src/native/.gitignore b/src/native/.gitignore deleted file mode 100644 index 06af5ee0acd..00000000000 --- a/src/native/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -CMakeUserPresets.json -CMakePresets.json -static-analysis.*.txt diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index a1cee1367a6..3c71fcf8580 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -155,10 +155,17 @@ include("${XA_BUILD_DIR}/xa_build_configuration.cmake") # Paths # if(IS_CLR_RUNTIME) - set(RUNTIME_DIR_ARM64 "${CORECLR_APP_RUNTIME_DIR_ARM64}") - set(RUNTIME_DIR_ARM "${CORECLR_APP_RUNTIME_DIR_ARM}") - set(RUNTIME_DIR_X86_64 "${CORECLR_APP_RUNTIME_DIR_X86_64}") - set(RUNTIME_DIR_X86 "${CORECLR_APP_RUNTIME_DIR_X86}") + if(LOCAL_CORECLR_PATH) + set(RUNTIME_DIR_ARM64 "${LOCAL_CORECLR_PATH}/runtimes/android-arm64") + set(RUNTIME_DIR_ARM "${LOCAL_CORECLR_PATH}/runtimes/android-arm") + set(RUNTIME_DIR_X86_64 "${LOCAL_CORECLR_PATH}/runtimes/android-x64") + set(RUNTIME_DIR_X86 "${LOCAL_CORECLR_PATH}/runtimes/android-x86") + else() + set(RUNTIME_DIR_ARM64 "${CORECLR_APP_RUNTIME_DIR_ARM64}") + set(RUNTIME_DIR_ARM "${CORECLR_APP_RUNTIME_DIR_ARM}") + set(RUNTIME_DIR_X86_64 "${CORECLR_APP_RUNTIME_DIR_X86_64}") + set(RUNTIME_DIR_X86 "${CORECLR_APP_RUNTIME_DIR_X86}") + endif() # TEMPORARY: for now JI needs to build with MonoVM embedding APIs set(TEMP_NETCORE_RUNTIME_DIR_ARM64 "${NETCORE_APP_RUNTIME_DIR_ARM64}") @@ -213,7 +220,13 @@ if(IS_MONO_RUNTIME) else() # TEMPORARY: for now JI needs to build with MonoVM embedding APIs set(TEMP_MONO_RUNTIME_INCLUDE_DIR ${TEMP_NETCORE_NET_RUNTIME_DIR}/native/include/mono-2.0) - set(RUNTIME_INCLUDE_DIR ${NET_RUNTIME_DIR}/native/include/clr) + + if(LOCAL_CORECLR_PATH) + set(CLR_REPO_ROOT_PATH "${LOCAL_CORECLR_PATH}/../../../..") + set(RUNTIME_INCLUDE_DIR "${CLR_REPO_ROOT_PATH}/src/native/corehost;${CLR_REPO_ROOT_PATH}/src/coreclr/hosts/inc") + else() + set(RUNTIME_INCLUDE_DIR ${REPO_ROOT_DIR}/src-ThirdParty/dotnet/runtime) + endif() endif() set(JAVA_INTEROP_INCLUDE_DIR ${JAVA_INTEROP_SRC_PATH}) diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt new file mode 100644 index 00000000000..5e1c6098da6 --- /dev/null +++ b/src/native/clr/host/CMakeLists.txt @@ -0,0 +1,163 @@ +# Needed modules + +include(CheckIncludeFile) +include(CheckCXXSymbolExists) + +set(BUILD_STATIC_LIBRARY OFF) + +if(DEBUG_BUILD) + # Convince NDK to really optimize our Debug builds. Without this, NDK's cmake toolchain definition + # will force a -O0 on us and our "debug" build is not really for debugging of our native code but + # rather for "debug" builds of user apps - it has extra code but it has to be as fast as possible. + set(XA_COMPILER_FLAGS_DEBUG "-fno-limit-debug-info -O2") + set(CMAKE_C_FLAGS_DEBUG ${XA_COMPILER_FLAGS_DEBUG}) + set(CMAKE_CXX_FLAGS_DEBUG ${XA_COMPILER_FLAGS_DEBUG}) +elseif(NOT ANALYZERS_ENABLED) + set(BUILD_STATIC_LIBRARY OFF) # Turn off for now, until we implement dynamic runtime linking at app build time +endif() + +# Library directories +set(XA_LIBRARY_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/lib/${ANDROID_RID}") +set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/libstubs/${ANDROID_RID}") + +# Header checks + +# Sources +string(TOLOWER ${CMAKE_BUILD_TYPE} XAMARIN_NET_ANDROID_SUFFIX) +set(XAMARIN_NET_ANDROID_LIB "net-android${CHECKED_BUILD_INFIX}.${XAMARIN_NET_ANDROID_SUFFIX}") +set(XAMARIN_NET_ANDROID_STATIC_LIB "${XAMARIN_NET_ANDROID_LIB}-static") + +set(XAMARIN_MONODROID_SOURCES + assembly-store.cc + host.cc + host-jni.cc + host-util.cc + internal-pinvokes.cc + os-bridge.cc + pinvoke-override.cc + typemap.cc +) + +list(APPEND LOCAL_CLANG_CHECK_SOURCES + ${XAMARIN_MONODROID_SOURCES} +) + +add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") + +# Build +add_library( + ${XAMARIN_NET_ANDROID_LIB} + SHARED ${XAMARIN_MONODROID_SOURCES} +) + +if(BUILD_STATIC_LIBRARY) + add_library( + ${XAMARIN_NET_ANDROID_STATIC_LIB} + STATIC + ${XAMARIN_MONODROID_SOURCES} + ) + set_static_library_suffix(${XAMARIN_NET_ANDROID_STATIC_LIB}) +endif() + +macro(lib_target_options TARGET_NAME) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + HAVE_CONFIG_H + HAVE_LZ4 + JI_DLL_EXPORT + JI_NO_VISIBILITY + ) + + if(DONT_INLINE) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + NO_INLINE + ) + endif() + + if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + DEBUG + ) + endif() + + if (ENABLE_TIMING) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + MONODROID_TIMING + ) + endif() + + target_compile_options( + ${TARGET_NAME} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} + ${XA_COMMON_CXX_ARGS} + ) + + target_include_directories( + ${TARGET_NAME} BEFORE + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/include + ${EXTERNAL_DIR} + ${ROBIN_MAP_DIR}/include + ) + + target_include_directories( + ${TARGET_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${RUNTIME_INCLUDE_DIR} + ${TEMP_MONO_RUNTIME_INCLUDE_DIR} + ${NATIVE_TRACING_INCLUDE_DIRS} + ${LIBUNWIND_INCLUDE_DIRS} + ) + + target_link_directories( + ${TARGET_NAME} + PRIVATE + ${NET_RUNTIME_DIR}/native + ) + + target_link_options( + ${TARGET_NAME} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} + ) + + target_link_libraries( + ${TARGET_NAME} + xa::xamarin-app + ${SHARED_LIB_NAME} + xa::xamarin-startup + xa::runtime-base + xa::java-interop +# xa::pinvoke-override-precompiled + xa::lz4 + -llog + -lcoreclr + ) +endmacro () + +lib_target_options(${XAMARIN_NET_ANDROID_LIB}) +xa_add_compile_definitions(${XAMARIN_NET_ANDROID_LIB}) +xa_add_include_directories(${XAMARIN_NET_ANDROID_LIB}) + +target_link_options(${XAMARIN_NET_ANDROID_LIB} + PRIVATE + -Wl,--version-script,${CMAKE_SOURCE_DIR}/clr/libnet-android.map.txt + -Wl,--no-undefined-version +) + +if(BUILD_STATIC_LIBRARY) + lib_target_options(${XAMARIN_NET_ANDROID_STATIC_LIB}) + xa_add_compile_definitions(${XAMARIN_NET_ANDROID_STATIC_LIB}) + xa_add_include_directories(${XAMARIN_NET_ANDROID_STATIC_LIB}) +endif() diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc new file mode 100644 index 00000000000..75ca4471dfd --- /dev/null +++ b/src/native/clr/host/assembly-store.cc @@ -0,0 +1,250 @@ +#include + +#if defined (HAVE_LZ4) +#include +#endif + +#include +#include +#include +#include +#include + +using namespace xamarin::android; + +[[gnu::always_inline]] +void AssemblyStore::set_assembly_data_and_size (uint8_t* source_assembly_data, uint32_t source_assembly_data_size, uint8_t*& dest_assembly_data, uint32_t& dest_assembly_data_size) noexcept +{ + dest_assembly_data = source_assembly_data; + dest_assembly_data_size = source_assembly_data_size; +} + +[[gnu::always_inline]] +auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name, bool force_rw) noexcept -> std::tuple +{ + uint8_t *assembly_data = nullptr; + uint32_t assembly_data_size = 0; + +#if defined (HAVE_LZ4) && defined (RELEASE) + auto header = reinterpret_cast(e.image_data); + if (header->magic == COMPRESSED_DATA_MAGIC) { + log_debug (LOG_ASSEMBLY, "Decompressing assembly '{}' from the assembly store", name); + if (compressed_assemblies.descriptors == nullptr) [[unlikely]] { + Helpers::abort_application (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined"sv); + } + if (header->descriptor_index >= compressed_assemblies.count) [[unlikely]] { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Invalid compressed assembly descriptor index {}", + header->descriptor_index + ) + ); + } + + CompressedAssemblyDescriptor &cad = compressed_assemblies.descriptors[header->descriptor_index]; + assembly_data_size = e.descriptor->data_size - sizeof(CompressedAssemblyHeader); + if (!cad.loaded) { + StartupAwareLock decompress_lock (assembly_decompress_mutex); + + if (cad.loaded) { + set_assembly_data_and_size (reinterpret_cast(cad.data), cad.uncompressed_file_size, assembly_data, assembly_data_size); + return {assembly_data, assembly_data_size}; + } + + if (cad.data == nullptr) [[unlikely]] { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Invalid compressed assembly descriptor at {}: no data", + header->descriptor_index + ) + ); + } + + if (header->uncompressed_length != cad.uncompressed_file_size) { + if (header->uncompressed_length > cad.uncompressed_file_size) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!", + name, + cad.uncompressed_file_size, + header->uncompressed_length + ) + ); + } else { + log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name); + } + cad.uncompressed_file_size = header->uncompressed_length; + } + + const char *data_start = pointer_add(e.image_data, sizeof(CompressedAssemblyHeader)); + int ret = LZ4_decompress_safe (data_start, reinterpret_cast(cad.data), static_cast(assembly_data_size), static_cast(cad.uncompressed_file_size)); + + if (ret < 0) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Decompression of assembly {} failed with code {}", + name, + ret + ) + ); + } + + if (static_cast(ret) != cad.uncompressed_file_size) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Decompression of assembly {} yielded a different size (expected {}, got {})", + name, + cad.uncompressed_file_size, + static_cast(ret) + ) + ); + } + cad.loaded = true; + } + + set_assembly_data_and_size (reinterpret_cast(cad.data), cad.uncompressed_file_size, assembly_data, assembly_data_size); + } else +#endif // def HAVE_LZ4 && def RELEASE + { + log_debug (LOG_ASSEMBLY, "Assembly '{}' is not compressed in the assembly store", name); + + // HACK! START + // Currently, MAUI crashes when we return a pointer to read-only data, so we must copy + // the assembly data to a read-write area. + log_debug (LOG_ASSEMBLY, "Copying assembly data to an r/w memory area"); + uint8_t *rw_pointer = static_cast(malloc (e.descriptor->data_size)); + memcpy (rw_pointer, e.image_data, e.descriptor->data_size); + set_assembly_data_and_size (rw_pointer, e.descriptor->data_size, assembly_data, assembly_data_size); + // HACK! END + // set_assembly_data_and_size (e.image_data, e.descriptor->data_size, assembly_data, assembly_data_size); + } + + return {assembly_data, assembly_data_size}; +} + +[[gnu::always_inline]] +auto AssemblyStore::find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept -> const AssemblyStoreIndexEntry* +{ + auto equal = [](AssemblyStoreIndexEntry const& entry, hash_t key) -> bool { return entry.name_hash == key; }; + auto less_than = [](AssemblyStoreIndexEntry const& entry, hash_t key) -> bool { return entry.name_hash < key; }; + ssize_t idx = Search::binary_search (hash, entries, entry_count); + if (idx >= 0) { + return &entries[idx]; + } + return nullptr; +} + +auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) noexcept -> void* +{ + hash_t name_hash = xxhash::hash (name.data (), name.length ()); + log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", optional_string (name.data ()), name_hash); + + const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); + if (hash_entry == nullptr) { + log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash 0x{:x}) not found", optional_string (name.data ()), name_hash); + return nullptr; + } + + if (hash_entry->descriptor_index >= assembly_store.assembly_count) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Invalid assembly descriptor index {}, exceeds the maximum value of {}", + hash_entry->descriptor_index, + assembly_store.assembly_count - 1 + ) + ); + } + + AssemblyStoreEntryDescriptor &store_entry = assembly_store.assemblies[hash_entry->descriptor_index]; + AssemblyStoreSingleAssemblyRuntimeData &assembly_runtime_info = assembly_store_bundled_assemblies[store_entry.mapping_index]; + + if (assembly_runtime_info.image_data == nullptr) { + // The assignments here don't need to be atomic, the value will always be the same, so even if two threads + // arrive here at the same time, nothing bad will happen. + assembly_runtime_info.image_data = assembly_store.data_start + store_entry.data_offset; + assembly_runtime_info.descriptor = &store_entry; + if (store_entry.debug_data_offset != 0) { + assembly_runtime_info.debug_info_data = assembly_store.data_start + store_entry.debug_data_offset; + } + + log_debug ( + LOG_ASSEMBLY, + "Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'", + static_cast(assembly_runtime_info.image_data), + static_cast(assembly_runtime_info.debug_info_data), + static_cast(assembly_runtime_info.config_data), + static_cast(assembly_runtime_info.descriptor), + assembly_runtime_info.descriptor->data_size, + assembly_runtime_info.descriptor->debug_data_size, + assembly_runtime_info.descriptor->config_data_size, + name + ); + } + + constexpr hash_t mscorlib_hash = 0x579a06fed6eec900; + auto [assembly_data, assembly_data_size] = get_assembly_data (assembly_runtime_info, name, name_hash == mscorlib_hash); + size = assembly_data_size; + return assembly_data; +} + +void AssemblyStore::map (int fd, std::string_view const& apk_path, std::string_view const& store_path, uint32_t offset, uint32_t size) noexcept +{ + detail::mmap_info assembly_store_map = Util::mmap_file (fd, offset, size, store_path); + + auto [payload_start, payload_size] = Util::get_wrapper_dso_payload_pointer_and_size (assembly_store_map, store_path); + log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); + auto header = static_cast(payload_start); + + auto get_full_store_path = [&apk_path, &store_path]() -> std::string { + std::string full_store_path; + + if (!apk_path.empty ()) { + full_store_path.append (apk_path); + // store path will be relative, to the apk + full_store_path.append ("!/"sv); + full_store_path.append (store_path); + } else { + full_store_path.append (store_path); + } + + return full_store_path; + }; + + if (header->magic != ASSEMBLY_STORE_MAGIC) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Assembly store '{}' is not a valid .NET for Android assembly store file", + get_full_store_path () + ) + ); + } + + if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", + get_full_store_path (), + header->version, + ASSEMBLY_STORE_FORMAT_VERSION + ) + ); + } + + constexpr size_t header_size = sizeof(AssemblyStoreHeader); + + assembly_store.data_start = static_cast(payload_start); + assembly_store.assembly_count = header->entry_count; + assembly_store.index_entry_count = header->index_entry_count; + assembly_store.assemblies = reinterpret_cast(assembly_store.data_start + header_size + header->index_size); + assembly_store_hashes = reinterpret_cast(assembly_store.data_start + header_size); + + log_debug (LOG_ASSEMBLY, "Mapped assembly store {}", get_full_store_path ()); +} diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc new file mode 100644 index 00000000000..e2055f45763 --- /dev/null +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -0,0 +1,753 @@ +// +// To build and run this utility run (on Linux or macOS): +// +// ../../../../build-tools/scripts/generate-pinvoke-tables.sh +// +// A reasonable C++20 compiler is required (g++ 10+, clang 11+, on mac it may require XCode 12.5 or newer) +// +// Whenever a new p/invoke (or entire new shared libary which is part of dotnet distribution) is added, try to keep the +// entries sorted alphabetically. This is not required by the generator but easier to examine by humans. +// +// If a new library is added, please remember to generate a hash of its name and update pinvoke-override-api.cc +// +// To get the list of exported native symbols for a library, you can run the following command on Unix: +// +// for s in $(llvm-nm -DUj [LIBRARY] | sort); do echo "\"$s\","; done +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace fs = std::filesystem; +using namespace xamarin::android; + +const std::vector internal_pinvoke_names = { +// "create_public_directory", +// "java_interop_free", +// "monodroid_clear_gdb_wait", +// "_monodroid_counters_dump", +// "_monodroid_detect_cpu_and_architecture", +// "monodroid_dylib_mono_free", +// "monodroid_dylib_mono_init", +// "monodroid_dylib_mono_new", +// "monodroid_embedded_assemblies_set_assemblies_prefix", +// "monodroid_fopen", + "monodroid_free", +// "_monodroid_freeifaddrs", +// "_monodroid_gc_wait_for_bridge_processing", +// "_monodroid_get_dns_servers", +// "monodroid_get_dylib", +// "_monodroid_getifaddrs", +// "monodroid_get_namespaced_system_property", +// "_monodroid_get_network_interface_supports_multicast", +// "_monodroid_get_network_interface_up_state", +// "monodroid_get_system_property", + "_monodroid_gref_get", + "_monodroid_gref_log", + "_monodroid_gref_log_delete", + "_monodroid_gref_log_new", + "monodroid_log", +// "monodroid_log_traces", +// "_monodroid_lookup_replacement_type", +// "_monodroid_lookup_replacement_method_info", +// "_monodroid_lref_log_delete", +// "_monodroid_lref_log_new", +// "_monodroid_max_gref_get", +// "monodroid_strdup_printf", +// "monodroid_strfreev", +// "monodroid_strsplit", +// "_monodroid_timezone_get_default_id", +// "monodroid_timing_start", +// "monodroid_timing_stop", + "monodroid_TypeManager_get_java_class_name", + "clr_typemap_managed_to_java", + "clr_typemap_java_to_managed", +// "_monodroid_weak_gref_delete", +// "_monodroid_weak_gref_get", +// "_monodroid_weak_gref_new", +// "path_combine", +// "recv_uninterrupted", +// "send_uninterrupted", +// "set_world_accessable", + +// We can treat liblog as "internal", since we link against it + "__android_log_print", +}; + +const std::vector dotnet_pinvoke_names = { + // libSystem.Globalization.Native.so + "GlobalizationNative_ChangeCase", + "GlobalizationNative_ChangeCaseInvariant", + "GlobalizationNative_ChangeCaseTurkish", + "GlobalizationNative_CloseSortHandle", + "GlobalizationNative_CompareString", + "GlobalizationNative_EndsWith", + "GlobalizationNative_EnumCalendarInfo", + "GlobalizationNative_GetCalendarInfo", + "GlobalizationNative_GetCalendars", + "GlobalizationNative_GetDefaultLocaleName", + "GlobalizationNative_GetICUVersion", + "GlobalizationNative_GetJapaneseEraStartDate", + "GlobalizationNative_GetLatestJapaneseEra", + "GlobalizationNative_GetLocaleInfoGroupingSizes", + "GlobalizationNative_GetLocaleInfoInt", + "GlobalizationNative_GetLocaleInfoString", + "GlobalizationNative_GetLocaleName", + "GlobalizationNative_GetLocales", + "GlobalizationNative_GetLocaleTimeFormat", + "GlobalizationNative_GetSortHandle", + "GlobalizationNative_GetSortKey", + "GlobalizationNative_GetSortVersion", + "GlobalizationNative_GetTimeZoneDisplayName", + "GlobalizationNative_IanaIdToWindowsId", + "GlobalizationNative_IndexOf", + "GlobalizationNative_InitICUFunctions", + "GlobalizationNative_InitOrdinalCasingPage", + "GlobalizationNative_IsNormalized", + "GlobalizationNative_IsPredefinedLocale", + "GlobalizationNative_LastIndexOf", + "GlobalizationNative_LoadICU", + "GlobalizationNative_NormalizeString", + "GlobalizationNative_StartsWith", + "GlobalizationNative_ToAscii", + "GlobalizationNative_ToUnicode", + "GlobalizationNative_WindowsIdToIanaId", + + // libSystem.IO.Compression.Native.so + "BrotliDecoderCreateInstance", + "BrotliDecoderDecompress", + "BrotliDecoderDecompressStream", + "BrotliDecoderDestroyInstance", + "BrotliDecoderErrorString", + "BrotliDecoderGetErrorCode", + "BrotliDecoderHasMoreOutput", + "BrotliDecoderIsFinished", + "BrotliDecoderIsUsed", + "BrotliDecoderSetParameter", + "BrotliDecoderTakeOutput", + "BrotliDecoderVersion", + "BrotliDefaultAllocFunc", + "BrotliDefaultFreeFunc", + "BrotliEncoderCompress", + "BrotliEncoderCompressStream", + "BrotliEncoderCreateInstance", + "BrotliEncoderDestroyInstance", + "BrotliEncoderHasMoreOutput", + "BrotliEncoderIsFinished", + "BrotliEncoderMaxCompressedSize", + "BrotliEncoderSetParameter", + "BrotliEncoderTakeOutput", + "BrotliEncoderVersion", + "BrotliGetDictionary", + "BrotliGetTransforms", + "BrotliSetDictionaryData", + "BrotliTransformDictionaryWord", + "CompressionNative_Crc32", + "CompressionNative_Deflate", + "CompressionNative_DeflateEnd", + "CompressionNative_DeflateInit2_", + "CompressionNative_Inflate", + "CompressionNative_InflateEnd", + "CompressionNative_InflateInit2_", + + // libSystem.Native.so + "SystemNative_Abort", + "SystemNative_Accept", + "SystemNative_Access", + "SystemNative_AlignedAlloc", + "SystemNative_AlignedFree", + "SystemNative_AlignedRealloc", + "SystemNative_Bind", + "SystemNative_Calloc", + "SystemNative_CanGetHiddenFlag", + "SystemNative_ChDir", + "SystemNative_ChMod", + "SystemNative_Close", + "SystemNative_CloseDir", + "SystemNative_CloseSocketEventPort", + "SystemNative_ConfigureTerminalForChildProcess", + "SystemNative_Connect", + "SystemNative_Connectx", + "SystemNative_ConvertErrorPalToPlatform", + "SystemNative_ConvertErrorPlatformToPal", + "SystemNative_CopyFile", + "SystemNative_CreateAutoreleasePool", + "SystemNative_CreateNetworkChangeListenerSocket", + "SystemNative_CreateSocketEventBuffer", + "SystemNative_CreateSocketEventPort", + "SystemNative_CreateThread", + "SystemNative_DisablePosixSignalHandling", + "SystemNative_Disconnect", + "SystemNative_DrainAutoreleasePool", + "SystemNative_Dup", + "SystemNative_EnablePosixSignalHandling", + "SystemNative_EnumerateGatewayAddressesForInterface", + "SystemNative_EnumerateInterfaceAddresses", + "SystemNative_Exit", + "SystemNative_FAllocate", + "SystemNative_FChflags", + "SystemNative_FChMod", + "SystemNative_FcntlCanGetSetPipeSz", + "SystemNative_FcntlGetFD", + "SystemNative_FcntlGetIsNonBlocking", + "SystemNative_FcntlGetPipeSz", + "SystemNative_FcntlSetFD", + "SystemNative_FcntlSetIsNonBlocking", + "SystemNative_FcntlSetPipeSz", + "SystemNative_FLock", + "SystemNative_ForkAndExecProcess", + "SystemNative_Free", + "SystemNative_FreeEnviron", + "SystemNative_FreeHostEntry", + "SystemNative_FreeLibrary", + "SystemNative_FreeSocketEventBuffer", + "SystemNative_FStat", + "SystemNative_FSync", + "SystemNative_FTruncate", + "SystemNative_FUTimens", + "SystemNative_GetActiveTcpConnectionInfos", + "SystemNative_GetActiveUdpListeners", + "SystemNative_GetAddressFamily", + "SystemNative_GetAllMountPoints", + "SystemNative_GetAtOutOfBandMark", + "SystemNative_GetBootTimeTicks", + "SystemNative_GetBytesAvailable", + "SystemNative_GetControlCharacters", + "SystemNative_GetControlMessageBufferSize", + "SystemNative_GetCpuUtilization", + "SystemNative_GetCryptographicallySecureRandomBytes", + "SystemNative_GetCwd", + "SystemNative_GetDefaultSearchOrderPseudoHandle", + "SystemNative_GetDefaultTimeZone", + "SystemNative_GetDeviceIdentifiers", + "SystemNative_GetDomainName", + "SystemNative_GetDomainSocketSizes", + "SystemNative_GetEGid", + "SystemNative_GetEnv", + "SystemNative_GetEnviron", + "SystemNative_GetErrNo", + "SystemNative_GetEstimatedTcpConnectionCount", + "SystemNative_GetEstimatedUdpListenerCount", + "SystemNative_GetEUid", + "SystemNative_GetFileSystemType", + "SystemNative_GetFormatInfoForMountPoint", + "SystemNative_GetGroupList", + "SystemNative_GetGroupName", + "SystemNative_GetGroups", + "SystemNative_GetHostEntryForName", + "SystemNative_GetHostName", + "SystemNative_GetIcmpv4GlobalStatistics", + "SystemNative_GetIcmpv6GlobalStatistics", + "SystemNative_GetIPv4Address", + "SystemNative_GetIPv4GlobalStatistics", + "SystemNative_GetIPv4MulticastOption", + "SystemNative_GetIPv6Address", + "SystemNative_GetIPv6MulticastOption", + "SystemNative_GetLingerOption", + "SystemNative_GetLoadLibraryError", + "SystemNative_GetMaximumAddressSize", + "SystemNative_GetNameInfo", + "SystemNative_GetNativeIPInterfaceStatistics", + "SystemNative_GetNetworkInterfaces", + "SystemNative_GetNonCryptographicallySecureRandomBytes", + "SystemNative_GetNumRoutes", + "SystemNative_GetOSArchitecture", + "SystemNative_GetPeerID", + "SystemNative_GetPeerName", + "SystemNative_GetPid", + "SystemNative_GetPlatformSignalNumber", + "SystemNative_GetPort", + "SystemNative_GetPriority", + "SystemNative_GetProcAddress", + "SystemNative_GetProcessPath", + "SystemNative_GetPwNamR", + "SystemNative_GetPwUidR", + "SystemNative_GetRawSockOpt", + "SystemNative_GetReadDirRBufferSize", + "SystemNative_GetRLimit", + "SystemNative_GetSid", + "SystemNative_GetSignalForBreak", + "SystemNative_GetSocketAddressSizes", + "SystemNative_GetSocketErrorOption", + "SystemNative_GetSocketType", + "SystemNative_GetSockName", + "SystemNative_GetSockOpt", + "SystemNative_GetSpaceInfoForMountPoint", + "SystemNative_GetSystemTimeAsTicks", + "SystemNative_GetTcpGlobalStatistics", + "SystemNative_GetTimestamp", + "SystemNative_GetTimeZoneData", + "SystemNative_GetUdpGlobalStatistics", + "SystemNative_GetUInt64OSThreadId", + "SystemNative_GetUnixRelease", + "SystemNative_GetUnixVersion", + "SystemNative_GetWindowSize", + "SystemNative_HandleNonCanceledPosixSignal", + "SystemNative_InitializeConsoleBeforeRead", + "SystemNative_InitializeTerminalAndSignalHandling", + "SystemNative_INotifyAddWatch", + "SystemNative_INotifyInit", + "SystemNative_INotifyRemoveWatch", + "SystemNative_InterfaceNameToIndex", + "SystemNative_iOSSupportVersion", + "SystemNative_IsATty", + "SystemNative_Kill", + "SystemNative_LChflags", + "SystemNative_LChflagsCanSetHiddenFlag", + "SystemNative_Link", + "SystemNative_Listen", + "SystemNative_LoadLibrary", + "SystemNative_LockFileRegion", + "SystemNative_Log", + "SystemNative_LogError", + "SystemNative_LowLevelMonitor_Acquire", + "SystemNative_LowLevelMonitor_Create", + "SystemNative_LowLevelMonitor_Destroy", + "SystemNative_LowLevelMonitor_Release", + "SystemNative_LowLevelMonitor_Signal_Release", + "SystemNative_LowLevelMonitor_TimedWait", + "SystemNative_LowLevelMonitor_Wait", + "SystemNative_LSeek", + "SystemNative_LStat", + "SystemNative_MAdvise", + "SystemNative_Malloc", + "SystemNative_MapTcpState", + "SystemNative_MkDir", + "SystemNative_MkdTemp", + "SystemNative_MkFifo", + "SystemNative_MkNod", + "SystemNative_MksTemps", + "SystemNative_MMap", + "SystemNative_MProtect", + "SystemNative_MSync", + "SystemNative_MUnmap", + "SystemNative_Open", + "SystemNative_OpenDir", + "SystemNative_PathConf", + "SystemNative_Pipe", + "SystemNative_PlatformSupportsDualModeIPv4PacketInfo", + "SystemNative_Poll", + "SystemNative_PosixFAdvise", + "SystemNative_PRead", + "SystemNative_PReadV", + "SystemNative_PWrite", + "SystemNative_PWriteV", + "SystemNative_Read", + "SystemNative_ReadDirR", + "SystemNative_ReadEvents", + "SystemNative_ReadLink", + "SystemNative_ReadProcessStatusInfo", + "SystemNative_ReadStdin", + "SystemNative_Realloc", + "SystemNative_RealPath", + "SystemNative_Receive", + "SystemNative_ReceiveMessage", + "SystemNative_ReceiveSocketError", + "SystemNative_RegisterForSigChld", + "SystemNative_Rename", + "SystemNative_RmDir", + "SystemNative_SchedGetAffinity", + "SystemNative_SchedGetCpu", + "SystemNative_SchedSetAffinity", + "SystemNative_SearchPath", + "SystemNative_SearchPath_TempDirectory", + "SystemNative_Send", + "SystemNative_SendFile", + "SystemNative_SendMessage", + "SystemNative_SetAddressFamily", + "SystemNative_SetDelayedSigChildConsoleConfigurationHandler", + "SystemNative_SetErrNo", + "SystemNative_SetEUid", + "SystemNative_SetIPv4Address", + "SystemNative_SetIPv4MulticastOption", + "SystemNative_SetIPv6Address", + "SystemNative_SetIPv6MulticastOption", + "SystemNative_SetKeypadXmit", + "SystemNative_SetLingerOption", + "SystemNative_SetPort", + "SystemNative_SetPosixSignalHandler", + "SystemNative_SetPriority", + "SystemNative_SetRawSockOpt", + "SystemNative_SetReceiveTimeout", + "SystemNative_SetRLimit", + "SystemNative_SetSendTimeout", + "SystemNative_SetSignalForBreak", + "SystemNative_SetSockOpt", + "SystemNative_SetTerminalInvalidationHandler", + "SystemNative_SetWindowSize", + "SystemNative_ShmOpen", + "SystemNative_ShmUnlink", + "SystemNative_Shutdown", + "SystemNative_SNPrintF", + "SystemNative_SNPrintF_1I", + "SystemNative_SNPrintF_1S", + "SystemNative_Socket", + "SystemNative_Stat", + "SystemNative_StdinReady", + "SystemNative_StrErrorR", + "SystemNative_SymLink", + "SystemNative_Sync", + "SystemNative_SysConf", + "SystemNative_Sysctl", + "SystemNative_SysLog", + "SystemNative_TryChangeSocketEventRegistration", + "SystemNative_TryGetIPPacketInformation", + "SystemNative_TryGetUInt32OSThreadId", + "SystemNative_UninitializeConsoleAfterRead", + "SystemNative_Unlink", + "SystemNative_UTimensat", + "SystemNative_WaitForSocketEvents", + "SystemNative_WaitIdAnyExitedNoHangNoWait", + "SystemNative_WaitPidExitedNoHang", + "SystemNative_Write", + + // libSystem.Security.Cryptography.Native.Android.so + "AndroidCryptoNative_AeadCipherFinalEx", + "AndroidCryptoNative_Aes128Cbc", + "AndroidCryptoNative_Aes128Ccm", + "AndroidCryptoNative_Aes128Cfb128", + "AndroidCryptoNative_Aes128Cfb8", + "AndroidCryptoNative_Aes128Ecb", + "AndroidCryptoNative_Aes128Gcm", + "AndroidCryptoNative_Aes192Cbc", + "AndroidCryptoNative_Aes192Ccm", + "AndroidCryptoNative_Aes192Cfb128", + "AndroidCryptoNative_Aes192Cfb8", + "AndroidCryptoNative_Aes192Ecb", + "AndroidCryptoNative_Aes192Gcm", + "AndroidCryptoNative_Aes256Cbc", + "AndroidCryptoNative_Aes256Ccm", + "AndroidCryptoNative_Aes256Cfb128", + "AndroidCryptoNative_Aes256Cfb8", + "AndroidCryptoNative_Aes256Ecb", + "AndroidCryptoNative_Aes256Gcm", + "AndroidCryptoNative_BigNumToBinary", + "AndroidCryptoNative_ChaCha20Poly1305", + "AndroidCryptoNative_CipherCreate", + "AndroidCryptoNative_CipherCreatePartial", + "AndroidCryptoNative_CipherCtxSetPadding", + "AndroidCryptoNative_CipherDestroy", + "AndroidCryptoNative_CipherFinalEx", + "AndroidCryptoNative_CipherIsSupported", + "AndroidCryptoNative_CipherReset", + "AndroidCryptoNative_CipherSetKeyAndIV", + "AndroidCryptoNative_CipherSetNonceLength", + "AndroidCryptoNative_CipherSetTagLength", + "AndroidCryptoNative_CipherUpdate", + "AndroidCryptoNative_CipherUpdateAAD", + "AndroidCryptoNative_DecodeRsaSubjectPublicKeyInfo", + "AndroidCryptoNative_DeleteGlobalReference", + "AndroidCryptoNative_Des3Cbc", + "AndroidCryptoNative_Des3Cfb64", + "AndroidCryptoNative_Des3Cfb8", + "AndroidCryptoNative_Des3Ecb", + "AndroidCryptoNative_DesCbc", + "AndroidCryptoNative_DesCfb8", + "AndroidCryptoNative_DesEcb", + "AndroidCryptoNative_DsaGenerateKey", + "AndroidCryptoNative_DsaKeyCreateByExplicitParameters", + "AndroidCryptoNative_DsaSign", + "AndroidCryptoNative_DsaSignatureFieldSize", + "AndroidCryptoNative_DsaSizeP", + "AndroidCryptoNative_DsaSizeSignature", + "AndroidCryptoNative_DsaVerify", + "AndroidCryptoNative_EcdhDeriveKey", + "AndroidCryptoNative_EcDsaSign", + "AndroidCryptoNative_EcDsaSize", + "AndroidCryptoNative_EcDsaVerify", + "AndroidCryptoNative_EcKeyCreateByExplicitParameters", + "AndroidCryptoNative_EcKeyCreateByKeyParameters", + "AndroidCryptoNative_EcKeyCreateByOid", + "AndroidCryptoNative_EcKeyDestroy", + "AndroidCryptoNative_EcKeyGetCurveName", + "AndroidCryptoNative_EcKeyGetSize", + "AndroidCryptoNative_EcKeyUpRef", + "AndroidCryptoNative_GetBigNumBytes", + "AndroidCryptoNative_GetDsaParameters", + "AndroidCryptoNative_GetECCurveParameters", + "AndroidCryptoNative_GetECKeyParameters", + "AndroidCryptoNative_GetRsaParameters", + "AndroidCryptoNative_NewGlobalReference", + "AndroidCryptoNative_Pbkdf2", + "AndroidCryptoNative_RegisterRemoteCertificateValidationCallback", + "AndroidCryptoNative_RsaCreate", + "AndroidCryptoNative_RsaDestroy", + "AndroidCryptoNative_RsaGenerateKeyEx", + "AndroidCryptoNative_RsaPrivateDecrypt", + "AndroidCryptoNative_RsaPublicEncrypt", + "AndroidCryptoNative_RsaSignPrimitive", + "AndroidCryptoNative_RsaSize", + "AndroidCryptoNative_RsaUpRef", + "AndroidCryptoNative_RsaVerificationPrimitive", + "AndroidCryptoNative_SetRsaParameters", + "AndroidCryptoNative_SSLGetSupportedProtocols", + "AndroidCryptoNative_SSLStreamCreate", + "AndroidCryptoNative_SSLStreamCreateWithCertificates", + "AndroidCryptoNative_SSLStreamCreateWithKeyStorePrivateKeyEntry", + "AndroidCryptoNative_SSLStreamGetApplicationProtocol", + "AndroidCryptoNative_SSLStreamGetCipherSuite", + "AndroidCryptoNative_SSLStreamGetPeerCertificate", + "AndroidCryptoNative_SSLStreamGetPeerCertificates", + "AndroidCryptoNative_SSLStreamGetProtocol", + "AndroidCryptoNative_SSLStreamHandshake", + "AndroidCryptoNative_SSLStreamInitialize", + "AndroidCryptoNative_SSLStreamIsLocalCertificateUsed", + "AndroidCryptoNative_SSLStreamRead", + "AndroidCryptoNative_SSLStreamRelease", + "AndroidCryptoNative_SSLStreamRequestClientAuthentication", + "AndroidCryptoNative_SSLStreamSetApplicationProtocols", + "AndroidCryptoNative_SSLStreamSetEnabledProtocols", + "AndroidCryptoNative_SSLStreamSetTargetHost", + "AndroidCryptoNative_SSLStreamShutdown", + "AndroidCryptoNative_SSLStreamVerifyHostname", + "AndroidCryptoNative_SSLStreamWrite", + "AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration", + "AndroidCryptoNative_X509ChainBuild", + "AndroidCryptoNative_X509ChainCreateContext", + "AndroidCryptoNative_X509ChainDestroyContext", + "AndroidCryptoNative_X509ChainGetCertificateCount", + "AndroidCryptoNative_X509ChainGetCertificates", + "AndroidCryptoNative_X509ChainGetErrorCount", + "AndroidCryptoNative_X509ChainGetErrors", + "AndroidCryptoNative_X509ChainSetCustomTrustStore", + "AndroidCryptoNative_X509ChainValidate", + "AndroidCryptoNative_X509Decode", + "AndroidCryptoNative_X509DecodeCollection", + "AndroidCryptoNative_X509Encode", + "AndroidCryptoNative_X509ExportPkcs7", + "AndroidCryptoNative_X509GetCertificateForPrivateKeyEntry", + "AndroidCryptoNative_X509GetContentType", + "AndroidCryptoNative_X509IsKeyStorePrivateKeyEntry", + "AndroidCryptoNative_X509PublicKey", + "AndroidCryptoNative_X509StoreAddCertificate", + "AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey", + "AndroidCryptoNative_X509StoreContainsCertificate", + "AndroidCryptoNative_X509StoreDeleteEntry", + "AndroidCryptoNative_X509StoreEnumerateCertificates", + "AndroidCryptoNative_X509StoreEnumerateTrustedCertificates", + "AndroidCryptoNative_X509StoreGetPrivateKeyEntry", + "AndroidCryptoNative_X509StoreOpenDefault", + "AndroidCryptoNative_X509StoreRemoveCertificate", + "CryptoNative_EnsureOpenSslInitialized", + "CryptoNative_ErrClearError", + "CryptoNative_ErrErrorStringN", + "CryptoNative_ErrGetErrorAlloc", + "CryptoNative_ErrPeekError", + "CryptoNative_ErrPeekLastError", + "CryptoNative_ErrReasonErrorString", + "CryptoNative_EvpDigestCurrent", + "CryptoNative_EvpDigestFinalEx", + "CryptoNative_EvpDigestOneShot", + "CryptoNative_EvpDigestReset", + "CryptoNative_EvpDigestUpdate", + "CryptoNative_EvpMd5", + "CryptoNative_EvpMdCtxCopyEx", + "CryptoNative_EvpMdCtxCreate", + "CryptoNative_EvpMdCtxDestroy", + "CryptoNative_EvpMdSize", + "CryptoNative_EvpSha1", + "CryptoNative_EvpSha256", + "CryptoNative_EvpSha384", + "CryptoNative_EvpSha512", + "CryptoNative_GetMaxMdSize", + "CryptoNative_GetRandomBytes", + "CryptoNative_HmacCreate", + "CryptoNative_HmacCurrent", + "CryptoNative_HmacDestroy", + "CryptoNative_HmacFinal", + "CryptoNative_HmacOneShot", + "CryptoNative_HmacReset", + "CryptoNative_HmacUpdate", + "Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate", +}; + +template +struct PinvokeEntry +{ + std::string name; + Hash hash; + bool write_func_pointer; + + template friend + Os& operator<< (Os& os, PinvokeEntry const& p) + { + os << std::showbase << std::hex << p.hash << ", \"" << p.name << "\", "; + + if (p.write_func_pointer) { + return os << "reinterpret_cast(&" << p.name << ")"; + } + + return os << "nullptr"; + } +}; + +void print (std::ostream& os, std::string comment, std::string variable_name, auto const& seq) +{ + os << "\t//" << comment << '\n'; + os << "\tstd::array " << variable_name << " {{" << std::endl; + + for (auto const& elem : seq) { + os << "\t\t{" << elem << "}," << std::endl; + } + + os << "\t}};" << std::endl << std::endl; +} + +template +bool add_hash (std::string const& pinvoke, Hash hash, std::vector>& vec, std::unordered_set& used_cache, bool write_func_pointer) +{ + vec.emplace_back (pinvoke, hash, write_func_pointer); + if (used_cache.contains (hash)) { + std::cerr << (sizeof(Hash) == 4 ? "32" : "64") << "-bit hash collision for key '" << pinvoke << "': " << std::hex << std::showbase << hash << std::endl; + return true; + } + + used_cache.insert (hash); + return false; +} + +bool generate_hashes (std::string table_name, std::vector const& names, std::vector>& pinvokes32, std::vector>& pinvokes64, bool write_func_pointer) +{ + std::unordered_set used_pinvokes32{}; + std::unordered_set used_pinvokes64{}; + uint32_t hash32; + uint64_t hash64; + bool have_collisions = false; + + std::cout << "There are " << names.size () << " " << table_name << " p/invoke functions" << std::endl; + for (std::string const& pinvoke : names) { + have_collisions |= add_hash (pinvoke, xxhash32::hash (pinvoke.c_str (), pinvoke.length ()), pinvokes32, used_pinvokes32, write_func_pointer); + have_collisions |= add_hash (pinvoke, xxhash64::hash (pinvoke.c_str (), pinvoke.length ()), pinvokes64, used_pinvokes64, write_func_pointer); + } + + std::cout << "p/invoke hash collisions for '" << table_name << "' were " << (have_collisions ? "" : "not ") << "found" << std::endl; + + std::ranges::sort (pinvokes32, {}, &PinvokeEntry::hash); + std::ranges::sort (pinvokes64, {}, &PinvokeEntry::hash); + + return have_collisions; +} + +template +void write_library_name_hash (Hash (*hasher)(const char*, size_t), std::ostream& os, std::string library_name, std::string variable_prefix) +{ + Hash hash = hasher (library_name.c_str (), library_name.length ()); + os << "constexpr hash_t " << variable_prefix << "_library_hash = " << std::hex << hash << ";" << std::endl; +} + +template +void write_library_name_hashes (Hash (*hasher)(const char*, size_t), std::ostream& output) +{ + write_library_name_hash (hasher, output, "java-interop", "java_interop"); + write_library_name_hash (hasher, output, "xa-internal-api", "xa_internal_api"); + write_library_name_hash (hasher, output, "liblog", "android_liblog"); + write_library_name_hash (hasher, output, "libSystem.Native", "system_native"); + write_library_name_hash (hasher, output, "libSystem.IO.Compression.Native", "system_io_compression_native"); + write_library_name_hash (hasher, output, "libSystem.Security.Cryptography.Native.Android", "system_security_cryptography_native_android"); + write_library_name_hash (hasher, output, "libSystem.Globalization.Native", "system_globalization_native"); +} + +int main (int argc, char **argv) +{ + if (argc < 2) { + std::cerr << "Usage: generate-pinvoke-tables OUTPUT_FILE_PATH" << std::endl << std::endl; + return 1; + } + + fs::path output_file_path {argv[1]}; + + if (fs::exists (output_file_path)) { + if (fs::is_directory (output_file_path)) { + std::cerr << "Output destination '" << output_file_path << "' is a directory" << std::endl; + return 1; + } + + fs::remove (output_file_path); + } else { + fs::path file_dir = output_file_path.parent_path (); + if (fs::exists (file_dir)) { + if (!fs::is_directory (file_dir)) { + std::cerr << "Output destination parent path points to a file ('" << file_dir << "'" << std::endl; + return 1; + } + } else if (!file_dir.empty ()) { + if (!fs::create_directories (file_dir)) { + std::cerr << "Failed to create output directory '" << file_dir << "'" << std::endl; + std::cerr << strerror (errno) << std::endl; + return 1; + } + } + } + + bool have_collisions = false; + std::vector> internal_pinvokes32{}; + std::vector> internal_pinvokes64{}; + have_collisions |= generate_hashes ("internal", internal_pinvoke_names, internal_pinvokes32, internal_pinvokes64, true); + + std::vector> dotnet_pinvokes32{}; + std::vector> dotnet_pinvokes64{}; + have_collisions |= generate_hashes ("dotnet", dotnet_pinvoke_names, dotnet_pinvokes32, dotnet_pinvokes64, false); + + std::cout << "Generating tables in file: " << output_file_path << std::endl; + + std::ofstream output {output_file_path, std::ios::binary}; + + output << "//" << std::endl; + output << "// Autogenarated file. DO NOT EDIT." << std::endl; + output << "//" << std::endl; + output << "// To regenerate run ../../../../build-tools/scripts/generate-pinvoke-tables.sh on Linux or macOS" << std::endl; + output << "// A compiler with support for C++20 ranges is required" << std::endl; + output << "//" << std::endl << std::endl; + + output << "#include " << std::endl; + output << "#include " << std::endl << std::endl; + + output << "namespace {" << std::endl; + output << "#if INTPTR_MAX == INT64_MAX" << std::endl; + print (output, "64-bit internal p/invoke table", "internal_pinvokes", internal_pinvokes64); + print (output, "64-bit DotNet p/invoke table", "dotnet_pinvokes", dotnet_pinvokes64); + output << std::endl; + write_library_name_hashes (xxhash64::hash, output); + + output << "#else" << std::endl; + + print (output, "32-bit internal p/invoke table", "internal_pinvokes", internal_pinvokes32); + print (output, "32-bit DotNet p/invoke table", "dotnet_pinvokes", dotnet_pinvokes32); + output << std::endl; + write_library_name_hashes (xxhash32::hash, output); + + output << "#endif" << std::endl << std::endl; + + output << "constexpr size_t internal_pinvokes_count = " << std::dec << std::noshowbase << internal_pinvoke_names.size () << ";" << std::endl; + output << "constexpr size_t dotnet_pinvokes_count = " << std::dec << std::noshowbase << dotnet_pinvoke_names.size () << ";" << std::endl; + output << "} // end of anonymous namespace" << std::endl; + + return have_collisions ? 1 : 0; +} + +// This serves as a quick compile-time test of the algorithm's correctness. +// The tests are copied from https://github.com/ekpyron/xxhashct/test.cpp + +template +struct constexpr_test { + static_assert (value == expected, "Compile-time hash mismatch."); +}; + +constexpr_test ("", 0), 0x2CC5D05U> constexprTest_1; +constexpr_test ("", 0), 0x36B78AE7U> constexprTest_2; +//constexpr_test ("", 0), 0xEF46DB3751D8E999ULL> constexprTest_3; +//constexpr_test ("", 0), 0xAC75FDA2929B17EFULL> constexprTest_4; +constexpr_test ("test", 4), 0x3E2023CFU> constexprTest32_5; +constexpr_test ("test", 4), 0xA9C14438U> constexprTest32_6; +//constexpr_test ("test", 4), 0x4fdcca5ddb678139ULL> constexprTest64_7; +//constexpr_test ("test", 4), 0x5A183B8150E2F651ULL> constexprTest64_8; diff --git a/src/native/clr/host/host-jni.cc b/src/native/clr/host/host-jni.cc new file mode 100644 index 00000000000..1b72015fc24 --- /dev/null +++ b/src/native/clr/host/host-jni.cc @@ -0,0 +1,60 @@ +#include +#include +#include + +using namespace xamarin::android; + +JNIEXPORT jint JNICALL +JNI_OnLoad (JavaVM *vm, void *reserved) +{ + log_write (LOG_DEFAULT, LogLevel::Info, "JNI_OnLoad"); + + return Host::Java_JNI_OnLoad (vm, reserved); +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_dumpTimingData ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass klass) +{ + // if (internal_timing == nullptr) { + // return; + // } + + // internal_timing.dump (); +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_register (JNIEnv *env, [[maybe_unused]] jclass klass, jstring managedType, jclass nativeClass, jstring methods) +{ + Host::Java_mono_android_Runtime_register (env, managedType, nativeClass, methods); +} + +JNIEXPORT void JNICALL +Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, + jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, + jobjectArray assembliesJava, jboolean isEmulator, + jboolean haveSplitApks) +{ + Host::Java_mono_android_Runtime_initInternal ( + env, + klass, + lang, + runtimeApksJava, + runtimeNativeLibDir, + appDirs, + localDateTimeOffset, + loader, + assembliesJava, + isEmulator, + haveSplitApks + ); +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_propagateUncaughtException (JNIEnv *env, [[maybe_unused]] jclass klass, jobject javaThread, jthrowable javaException) +{ +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_notifyTimeZoneChanged ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass klass) +{ +} diff --git a/src/native/clr/host/host-util.cc b/src/native/clr/host/host-util.cc new file mode 100644 index 00000000000..1a1e49d8e34 --- /dev/null +++ b/src/native/clr/host/host-util.cc @@ -0,0 +1,19 @@ +#include +#include + +using namespace xamarin::android; + +auto HostUtil::get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) noexcept -> jclass +{ + static constexpr char java_lang_class_sig[] = "Ljava/lang/Class;"; + + jfieldID fieldID = env->GetStaticFieldID (runtime, name, java_lang_class_sig); + if (fieldID == nullptr) + return nullptr; + + jobject field = env->GetStaticObjectField (runtime, fieldID); + if (field == nullptr) + return nullptr; + + return reinterpret_cast (make_gref ? OSBridge::lref_to_gref (env, field) : field); +} diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc new file mode 100644 index 00000000000..a2eedaa2d6d --- /dev/null +++ b/src/native/clr/host/host.cc @@ -0,0 +1,393 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace xamarin::android; + +void Host::clr_error_writer (const char *message) noexcept +{ + log_error (LOG_DEFAULT, "CLR error: {}", optional_string (message)); +} + +size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept +{ + log_debug (LOG_DEFAULT, "clr_get_runtime_property (\"{}\"...)", key); + return 0; +} + +bool Host::clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept +{ + // TODO: `path` might be a full path, make sure it isn't + log_debug (LOG_DEFAULT, "clr_external_assembly_probe (\"{}\"...)", path); + if (data_start == nullptr || size == nullptr) { + return false; // TODO: abort instead? + } + + *data_start = AssemblyStore::open_assembly (path, *size); + log_debug ( + LOG_ASSEMBLY, + "Assembly data {}mapped ({:p}, {} bytes)", + *data_start == nullptr ? "not "sv : ""sv, + *data_start, + *size + ); + + return *data_start != nullptr && *size > 0; +} + +auto Host::zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size) -> bool +{ + log_debug (LOG_ASSEMBLY, "zip entry: {}", entry_name.get ()); + if (!found_assembly_store) { + found_assembly_store = Zip::assembly_store_file_path.compare (0, entry_name.length (), entry_name.get ()) == 0; + if (found_assembly_store) { + log_debug (LOG_ASSEMBLY, "Found assembly store in '{}': {}", apk_path, Zip::assembly_store_file_path); + AssemblyStore::map (apk_fd, apk_path, Zip::assembly_store_file_path, offset, size); + return false; // This will make the scanner keep the APK open + } + } + return false; +} + +void Host::gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks) +{ + if (!AndroidSystem::is_embedded_dso_mode_enabled ()) { + Helpers::abort_application ("Filesystem mode not supported yet."); + } + + int64_t apk_count = static_cast(runtimeApks.get_length ()); + bool got_split_config_abi_apk = false; + + for (int64_t i = 0; i < apk_count; i++) { + std::string_view apk_file = runtimeApks [static_cast(i)].get_string_view (); + + if (have_split_apks) { + bool scan_apk = false; + + // With split configs we need to scan only the abi apk, because both the assembly stores and the runtime + // configuration blob are in `lib/{ARCH}`, which in turn lives in the split config APK + if (!got_split_config_abi_apk && apk_file.ends_with (Constants::split_config_abi_apk_name.data ())) { + got_split_config_abi_apk = scan_apk = true; + } + + if (!scan_apk) { + continue; + } + } + + Zip::scan_archive (apk_file, zip_scan_callback); + } +} + +void Host::create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept +{ + static_local_string dir (home_len + relative_path.length ()); + Util::path_combine (dir, home.get_string_view (), relative_path); + + log_debug (LOG_DEFAULT, "Creating XDG directory: {}", optional_string (dir.get ())); + int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE); + if (rv < 0 && errno != EEXIST) { + log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", optional_string (dir.get ()), strerror (errno)); + } + + if (!environment_variable_name.empty ()) { + setenv (environment_variable_name.data (), dir.get (), 1); + } +} + +void Host::create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept +{ + size_t home_len = strlen (homeDir.get_cstr ()); + + constexpr auto XDG_DATA_HOME = "XDG_DATA_HOME"sv; + constexpr auto HOME_PATH = ".local/share"sv; + create_xdg_directory (homeDir, home_len, HOME_PATH, XDG_DATA_HOME); + + constexpr auto XDG_CONFIG_HOME = "XDG_CONFIG_HOME"sv; + constexpr auto CONFIG_PATH = ".config"sv; + create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME); +} + +[[gnu::always_inline]] +auto Host::create_delegate ( + std::string_view const& assembly_name, std::string_view const& type_name, + std::string_view const& method_name) noexcept -> void* +{ + void *delegate = nullptr; + int hr = coreclr_create_delegate ( + clr_host, + domain_id, + assembly_name.data (), + type_name.data (), + method_name.data (), + &delegate + ); + log_debug (LOG_ASSEMBLY, + "{}@{}.{} delegate creation result == {:x}; delegate == {:p}", + assembly_name, + type_name, + method_name, + static_cast(hr), + delegate + ); + + // TODO: make S_OK & friends known to us + if (hr != 0 /* S_OK */) { + Helpers::abort_application ( + LOG_DEFAULT, + std::format ( + "Failed to create delegate for {}.{}.{} (result == {:x})", + assembly_name, + type_name, + method_name, + hr) + ); + } + + return delegate; +} + +void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeClass, jstring lang, jobjectArray runtimeApksJava, + jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, + jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) noexcept +{ + Logger::init_logging_categories (); + + // If fast logging is disabled, log messages immediately + FastTiming::initialize ((Logger::log_timing_categories() & LogTimingCategories::FastBare) != LogTimingCategories::FastBare); + + size_t total_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + _timing = std::make_unique (); + total_time_index = internal_timing.start_event (TimingEventKind::TotalRuntimeInit); + } + + jstring_array_wrapper applicationDirs (env, appDirs); + + jstring_wrapper jstr (env, lang); + Util::set_environment_variable ("LANG", jstr); + + jstring_wrapper &home = applicationDirs[Constants::APP_DIRS_FILES_DIR_INDEX]; + Util::set_environment_variable_for_directory ("TMPDIR", applicationDirs[Constants::APP_DIRS_CACHE_DIR_INDEX]); + Util::set_environment_variable_for_directory ("HOME", home); + create_xdg_directories_and_environment (home); + + AndroidSystem::detect_embedded_dso_mode (applicationDirs); + AndroidSystem::set_running_in_emulator (isEmulator); + AndroidSystem::set_primary_override_dir (home); + AndroidSystem::create_update_dir (AndroidSystem::get_primary_override_dir ()); + AndroidSystem::setup_environment (); + + jstring_array_wrapper runtimeApks (env, runtimeApksJava); + AndroidSystem::setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); + + gather_assemblies_and_libraries (runtimeApks, haveSplitApks); + + size_t clr_init_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + clr_init_time_index = internal_timing.start_event (TimingEventKind::MonoRuntimeInit); + } + + coreclr_set_error_writer (clr_error_writer); + // We REALLY shouldn't be doing this + snprintf (host_contract_ptr_buffer.data (), host_contract_ptr_buffer.size (), "%p", &runtime_contract); + + // The first entry in the property arrays is for the host contract pointer. Application build makes sure + // of that. + init_runtime_property_values[0] = host_contract_ptr_buffer.data (); + int hr = coreclr_initialize ( + application_config.android_package_name, + "Xamarin.Android", + (int)application_config.number_of_runtime_properties, + init_runtime_property_names, + const_cast(init_runtime_property_values), + &clr_host, + &domain_id + ); + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.end_event (clr_init_time_index); + } + + // TODO: make S_OK & friends known to us + if (hr != 0 /* S_OK */) { + Helpers::abort_application ( + LOG_DEFAULT, + std::format ( + "Failed to initialize CoreCLR. Error code: {:x}", + static_cast(hr) + ) + ); + } + + abort_unless ( + clr_host != nullptr, + [&hr] { + return detail::_format_message ("Failure to initialize CoreCLR host instance. Returned result 0x%x", static_cast(hr)); + } + ); + + struct JnienvInitializeArgs init = {}; + init.runtimeType = RuntimeTypeCoreCLR; + init.javaVm = jvm; + init.env = env; + init.logCategories = log_categories; + init.version = env->GetVersion (); + init.isRunningOnDesktop = false; + init.brokenExceptionTransitions = 0; + init.packageNamingPolicy = static_cast(application_config.package_naming_policy); + init.boundExceptionType = 0; // System + init.jniAddNativeMethodRegistrationAttributePresent = application_config.jni_add_native_method_registration_attribute_present ? 1 : 0; + init.jniRemappingInUse = application_config.jni_remapping_replacement_type_count > 0 || application_config.jni_remapping_replacement_method_index_entry_count > 0; + init.marshalMethodsEnabled = application_config.marshal_methods_enabled; + + // GC threshold is 90% of the max GREF count + init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); + init.grefClass = HostUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); + Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); + + jclass lrefLoaderClass = env->GetObjectClass (loader); + init.Loader_loadClass = env->GetMethodID (lrefLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + env->DeleteLocalRef (lrefLoaderClass); + + init.grefLoader = env->NewGlobalRef (loader); + init.grefIGCUserPeer = HostUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true); + init.grefGCUserPeerable = HostUtil::get_class_from_runtime_field (env, runtimeClass, "net_dot_jni_GCUserPeerable", true); + + log_info (LOG_GC, "GREF GC Threshold: {}", init.grefGcThreshold); + + // TODO: GC bridge to initialize here + + OSBridge::initialize_on_runtime_init (env, runtimeClass); + + size_t native_to_managed_index; + if (FastTiming::enabled ()) [[unlikely]] { + native_to_managed_index = internal_timing.start_event (TimingEventKind::NativeToManagedTransition); + } + + void *delegate = nullptr; + log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.RegisterJniNatives", Constants::JNIENVINIT_FULL_TYPE_NAME); + delegate = create_delegate (Constants::MONO_ANDROID_ASSEMBLY_NAME, Constants::JNIENVINIT_FULL_TYPE_NAME, "RegisterJniNatives"sv); + jnienv_register_jni_natives = reinterpret_cast (delegate); + abort_unless ( + jnienv_register_jni_natives != nullptr, + [] { + return detail::_format_message ( + "Failed to obtain unmanaged-callers-only pointer to the %s.%s.RegisterJniNatives method.", + Constants::MONO_ANDROID_ASSEMBLY_NAME, + Constants::JNIENVINIT_FULL_TYPE_NAME + ); + } + ); + + log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.Initialize", Constants::JNIENVINIT_FULL_TYPE_NAME); + delegate = create_delegate (Constants::MONO_ANDROID_ASSEMBLY_NAME, Constants::JNIENVINIT_FULL_TYPE_NAME, "Initialize"sv); + auto initialize = reinterpret_cast (delegate); + abort_unless ( + initialize != nullptr, + [] { + return detail::_format_message ( + "Failed to obtain unmanaged-callers-only pointer to the %s.%s.Initialize method.", + Constants::MONO_ANDROID_ASSEMBLY_NAME, + Constants::JNIENVINIT_FULL_TYPE_NAME + ); + } + ); + + log_debug (LOG_DEFAULT, "Calling into managed runtime init"sv); + initialize (&init); + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.end_event (native_to_managed_index); + internal_timing.end_event (total_time_index); + } +} + +void Host::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods) noexcept +{ + size_t total_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + total_time_index = internal_timing.start_event (TimingEventKind::RuntimeRegister); + } + + jsize managedType_len = env->GetStringLength (managedType); + const jchar *managedType_ptr = env->GetStringChars (managedType, nullptr); + int methods_len = env->GetStringLength (methods); + const jchar *methods_ptr = env->GetStringChars (methods, nullptr); + + // TODO: must attach thread to the runtime here + jnienv_register_jni_natives (managedType_ptr, managedType_len, nativeClass, methods_ptr, methods_len); + + env->ReleaseStringChars (methods, methods_ptr); + env->ReleaseStringChars (managedType, managedType_ptr); + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.end_event (total_time_index, true /* uses_more_info */); + + dynamic_local_string type; + const char *mt_ptr = env->GetStringUTFChars (managedType, nullptr); + type.assign (mt_ptr, strlen (mt_ptr)); + env->ReleaseStringUTFChars (managedType, mt_ptr); + + internal_timing.add_more_info (total_time_index, type); + } +} + +auto Host::get_java_class_name_for_TypeManager (jclass klass) noexcept -> char* +{ + if (klass == nullptr || Class_getName == nullptr) { + return nullptr; + } + + JNIEnv *env = OSBridge::ensure_jnienv (); + jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); + if (name == nullptr) { + log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); + return nullptr; + } + + const char *mutf8 = env->GetStringUTFChars (name, nullptr); + if (mutf8 == nullptr) { + log_error (LOG_DEFAULT, "Failed to convert Java class name to UTF8 (out of memory?)"sv); + env->DeleteLocalRef (name); + return nullptr; + } + char *ret = strdup (mutf8); + + env->ReleaseStringUTFChars (name, mutf8); + env->DeleteLocalRef (name); + + char *dot = strchr (ret, '.'); + while (dot != nullptr) { + *dot = '/'; + dot = strchr (dot + 1, '.'); + } + + return ret; +} + +auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint +{ + log_write (LOG_DEFAULT, LogLevel::Info, "Host OnLoad"); + jvm = vm; + + JNIEnv *env = nullptr; + vm->GetEnv ((void**)&env, JNI_VERSION_1_6); + OSBridge::initialize_on_onload (vm, env); + + AndroidSystem::init_max_gref_count (); + return JNI_VERSION_1_6; +} diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc new file mode 100644 index 00000000000..39562e12ec5 --- /dev/null +++ b/src/native/clr/host/internal-pinvokes.cc @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +using namespace xamarin::android; + +int _monodroid_gref_get () noexcept +{ + return OSBridge::get_gc_gref_count (); +} + +void _monodroid_gref_log (const char *message) noexcept +{ +} + +int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept +{ + return OSBridge::_monodroid_gref_log_new (curHandle, curType, newHandle, newType, threadName, threadId, from, from_writable); +} + +void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept +{ +} + +const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept +{ + return TypeMapper::typemap_managed_to_java (typeName, mvid); +} + +bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept +{ + return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); +} + +void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept +{ + switch (level) { + case LogLevel::Verbose: + case LogLevel::Debug: + log_debug_nocheck (category, std::string_view { message }); + break; + + case LogLevel::Info: + log_info_nocheck (category, std::string_view { message }); + break; + + case LogLevel::Warn: + case LogLevel::Silent: // warn is always printed + log_warn (category, std::string_view { message }); + break; + + case LogLevel::Error: + log_error (category, std::string_view { message }); + break; + + case LogLevel::Fatal: + log_fatal (category, std::string_view { message }); + break; + + default: + case LogLevel::Unknown: + case LogLevel::Default: + log_info_nocheck (category, std::string_view { message }); + break; + } +} + +char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept +{ + return Host::get_java_class_name_for_TypeManager (klass); +} + +void monodroid_free (void *ptr) noexcept +{ + free (ptr); +} diff --git a/src/native/clr/host/os-bridge.cc b/src/native/clr/host/os-bridge.cc new file mode 100644 index 00000000000..a2ec0492340 --- /dev/null +++ b/src/native/clr/host/os-bridge.cc @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include + +using namespace xamarin::android; + +void OSBridge::initialize_on_onload (JavaVM *vm, JNIEnv *env) noexcept +{ + abort_if_invalid_pointer_argument (env, "env"); + abort_if_invalid_pointer_argument (vm, "vm"); + + jvm = vm; + // jclass lref = env->FindClass ("java/lang/Runtime"); + // jmethodID Runtime_getRuntime = env->GetStaticMethodID (lref, "getRuntime", "()Ljava/lang/Runtime;"); + + // Runtime_gc = env->GetMethodID (lref, "gc", "()V"); + // Runtime_instance = lref_to_gref (env, env->CallStaticObjectMethod (lref, Runtime_getRuntime)); + // env->DeleteLocalRef (lref); + // lref = env->FindClass ("java/lang/ref/WeakReference"); + // weakrefClass = reinterpret_cast (env->NewGlobalRef (lref)); + // env->DeleteLocalRef (lref); + // weakrefCtor = env->GetMethodID (weakrefClass, "", "(Ljava/lang/Object;)V"); + // weakrefGet = env->GetMethodID (weakrefClass, "get", "()Ljava/lang/Object;"); + + // abort_unless ( + // weakrefClass != nullptr && weakrefCtor != nullptr && weakrefGet != nullptr, + // "Failed to look up required java.lang.ref.WeakReference members" + // ); +} + +void OSBridge::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept +{ + abort_if_invalid_pointer_argument (env, "env"); + GCUserPeer_class = HostUtil::get_class_from_runtime_field(env, runtimeClass, "mono_android_GCUserPeer", true); + GCUserPeer_ctor = env->GetMethodID (GCUserPeer_class, "", "()V"); + abort_unless (GCUserPeer_class != nullptr && GCUserPeer_ctor != nullptr, "Failed to load mono.android.GCUserPeer!"); +} + +auto OSBridge::lref_to_gref (JNIEnv *env, jobject lref) noexcept -> jobject +{ + if (lref == 0) { + return 0; + } + + jobject g = env->NewGlobalRef (lref); + env->DeleteLocalRef (lref); + return g; +} + +auto OSBridge::_monodroid_gref_inc () noexcept -> int +{ + return __sync_add_and_fetch (&gc_gref_count, 1); +} + +auto OSBridge::_monodroid_gref_dec () noexcept -> int +{ + return __sync_sub_and_fetch (&gc_gref_count, 1); +} + +[[gnu::always_inline]] +auto OSBridge::_get_stack_trace_line_end (char *m) noexcept -> char* +{ + while (*m && *m != '\n') { + m++; + } + + return m; +} + +[[gnu::always_inline]] +void OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) noexcept +{ + char *n = const_cast (from); + + char c; + do { + char *m = n; + char *end = _get_stack_trace_line_end (m); + + n = end + 1; + c = *end; + *end = '\0'; + if ((category == LOG_GREF && Logger::gref_to_logcat ()) || + (category == LOG_LREF && Logger::lref_to_logcat ())) { + log_debug (category, "{}", optional_string (m)); + } + + if (to != nullptr) { + fprintf (to, "%s\n", optional_string (m)); + fflush (to); + } + *end = c; + } while (c); +} + +void OSBridge::_monodroid_gref_log (const char *message) noexcept +{ + if (Logger::gref_to_logcat ()) { + log_debug (LOG_GREF, "{}", optional_string (message)); + } + + if (Logger::gref_log () == nullptr) { + return; + } + + fprintf (Logger::gref_log (), "%s", optional_string (message)); + fflush (Logger::gref_log ()); +} + +auto OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept -> int +{ + int c = _monodroid_gref_inc (); + if ((log_categories & LOG_GREF) == 0) { + return c; + } + + log_info (LOG_GREF, + "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + optional_string (threadName), + threadId + ); + + if (Logger::gref_to_logcat ()) { + if (from_writable) { + _write_stack_trace (nullptr, const_cast(from), LOG_GREF); + } else { + log_info (LOG_GREF, "{}", optional_string (from)); + } + } + + if (Logger::gref_log () == nullptr) { + return c; + } + + fprintf ( + Logger::gref_log (), + "+g+ grefc %i gwrefc %i obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%i)\n", + c, + gc_weak_gref_count, + curHandle, + curType, + newHandle, + newType, + optional_string (threadName), + threadId + ); + + if (from_writable) { + _write_stack_trace (Logger::gref_log (), const_cast(from)); + } else { + fprintf (Logger::gref_log (), "%s\n", from); + } + + fflush (Logger::gref_log ()); + return c; +} + +void OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept +{ + int c = _monodroid_gref_dec (); + if ((log_categories & LOG_GREF) == 0) { + return; + } + + log_info (LOG_GREF, + "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + optional_string (threadName), + threadId + ); + if (Logger::gref_to_logcat ()) { + if (from_writable) { + _write_stack_trace (nullptr, const_cast(from), LOG_GREF); + } else { + log_info (LOG_GREF, "{}", optional_string (from)); + } + } + + if (Logger::gref_log () == nullptr) { + return; + } + + fprintf (Logger::gref_log (), + "-g- grefc %i gwrefc %i handle %p/%c from thread '%s'(%i)\n", + c, + gc_weak_gref_count, + handle, + type, + optional_string (threadName), + threadId + ); + + if (from_writable) { + _write_stack_trace (Logger::gref_log (), const_cast(from)); + } else { + fprintf (Logger::gref_log(), "%s\n", optional_string (from)); + } + + fflush (Logger::gref_log ()); +} diff --git a/src/native/clr/host/pinvoke-override.cc b/src/native/clr/host/pinvoke-override.cc new file mode 100644 index 00000000000..d1467e4eda1 --- /dev/null +++ b/src/native/clr/host/pinvoke-override.cc @@ -0,0 +1,105 @@ +#include +#include +#include + +using namespace xamarin::android; + +#include "pinvoke-tables.include" + +[[gnu::flatten]] +auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const char *entrypoint_name) noexcept -> void* +{ + if (library_name == nullptr || entrypoint_name == nullptr) { + return nullptr; + } + + hash_t library_name_hash = xxhash::hash (library_name, strlen (library_name)); + hash_t entrypoint_hash = xxhash::hash (entrypoint_name, strlen (entrypoint_name)); + + if (library_name_hash == java_interop_library_hash || library_name_hash == xa_internal_api_library_hash || library_name_hash == android_liblog_library_hash) { + PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); + + if (entry == nullptr) [[unlikely]] { + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", + optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); + log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); + for (size_t i = 0uz; i < internal_pinvokes_count; i++) { + PinvokeEntry const& e = internal_pinvokes[i]; + log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", optional_string (e.name), e.func, e.hash); + } + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Failure handling a p/invoke request for '{}'@'{}'", + optional_string (entrypoint_name), + optional_string (library_name) + ) + ); + } + + return entry->func; + } + + // The order of statements below should be kept in the descending probability of occurrence order (as much as + // possible, of course). `libSystem.Native` is requested during early startup for each MAUI app, so its + // probability is higher, just as it's more likely that `libSystem.Security.Cryptography.Android` will be used + // in an app rather than `libSystem.IO.Compression.Native` + void **dotnet_dso_handle; // Set to a non-null value only for dotnet shared libraries + if (library_name_hash == system_native_library_hash) { + dotnet_dso_handle = &system_native_library_handle; + } else if (library_name_hash == system_security_cryptography_native_android_library_hash) { + dotnet_dso_handle = &system_security_cryptography_native_android_library_handle; + } else if (library_name_hash == system_io_compression_native_library_hash) { + dotnet_dso_handle = &system_io_compression_native_library_handle; + } else if (library_name_hash == system_globalization_native_library_hash) { + dotnet_dso_handle = &system_globalization_native_library_handle; + } else { + dotnet_dso_handle = nullptr; + } + + if (dotnet_dso_handle != nullptr) { + PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, dotnet_pinvokes.data (), dotnet_pinvokes_count); + if (entry != nullptr) { + if (entry->func != nullptr) { + return entry->func; + } + + load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); + if (entry->func == nullptr) { + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", + optional_string (entrypoint_name), optional_string (library_name)); + return nullptr; // let Mono deal with the fallout + } + + return entry->func; + } + + // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below + log_debug ( + LOG_ASSEMBLY, + "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", + optional_string (entrypoint_name), + optional_string (library_name) + ); + + // This is temporary, to catch p/invokes we might be missing that are used in the default templates + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Missing pinvoke {}@{}", + optional_string (entrypoint_name), + optional_string (library_name) + ) + ); + } + + return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); +} + +const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept +{ + log_debug (LOG_ASSEMBLY, "clr_pinvoke_override (\"{}\", \"{}\")", library_name, entry_point_name); + void *ret = PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); + log_debug (LOG_DEFAULT, "p/invoke {}found", ret == nullptr ? "not"sv : ""sv); + return ret; +} diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include new file mode 100644 index 00000000000..73d07f125c6 --- /dev/null +++ b/src/native/clr/host/pinvoke-tables.include @@ -0,0 +1,1024 @@ +// +// Autogenarated file. DO NOT EDIT. +// +// To regenerate run ../../../../build-tools/scripts/generate-pinvoke-tables.sh on Linux or macOS +// A compiler with support for C++20 ranges is required +// + +#include +#include + +namespace { +#if INTPTR_MAX == INT64_MAX + //64-bit internal p/invoke table + std::array internal_pinvokes {{ + {0x4310c1531ddddc14, "__android_log_print", reinterpret_cast(&__android_log_print)}, + {0x4b1956138764939a, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, + {0x9187e6bc6294cacf, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, + {0x9a946dfe9916a942, "clr_typemap_java_to_managed", reinterpret_cast(&clr_typemap_java_to_managed)}, + {0xa7f58f3ee428cc6b, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, + {0xae3df96dda0143bd, "_monodroid_gref_log", reinterpret_cast(&_monodroid_gref_log)}, + {0xb8306f71b963cd3d, "monodroid_log", reinterpret_cast(&monodroid_log)}, + {0xd1e121b94ea63f2e, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, + {0xd5151b00eb33d85e, "monodroid_TypeManager_get_java_class_name", reinterpret_cast(&monodroid_TypeManager_get_java_class_name)}, + {0xf41c48df6f9be476, "monodroid_free", reinterpret_cast(&monodroid_free)}, + }}; + + //64-bit DotNet p/invoke table + std::array dotnet_pinvokes {{ + {0x99f2ee02463000, "CompressionNative_Crc32", nullptr}, + {0xb38afc8bfe830b, "SystemNative_Bind", nullptr}, + {0x190fe65d8736dcb, "SystemNative_TryGetIPPacketInformation", nullptr}, + {0x1c8b86562ad5772, "SystemNative_Receive", nullptr}, + {0x202543f28ecaf06, "SystemNative_Abort", nullptr}, + {0x25abeafa88904a2, "SystemNative_SetPosixSignalHandler", nullptr}, + {0x33158212a812caf, "SystemNative_GetEstimatedTcpConnectionCount", nullptr}, + {0x3511e36d0a6c1b5, "SystemNative_LockFileRegion", nullptr}, + {0x375a0e90c77ca35, "AndroidCryptoNative_EcKeyCreateByExplicitParameters", nullptr}, + {0x37b9dd562235e42, "SystemNative_MSync", nullptr}, + {0x3a5df4793dd3230, "SystemNative_INotifyInit", nullptr}, + {0x3d24547fa4fc31b, "SystemNative_GetUInt64OSThreadId", nullptr}, + {0x410f8526b1edfc3, "GlobalizationNative_GetLocaleInfoInt", nullptr}, + {0x47302bd7e277183, "AndroidCryptoNative_X509GetCertificateForPrivateKeyEntry", nullptr}, + {0x581df5b0a00c422, "SystemNative_SetRLimit", nullptr}, + {0x598db66ca39c41f, "AndroidCryptoNative_EcKeyUpRef", nullptr}, + {0x5b5ab451ff38f8e, "SystemNative_GetMaximumAddressSize", nullptr}, + {0x656cac62ccc9e3c, "AndroidCryptoNative_X509GetContentType", nullptr}, + {0x6861b5336291d12, "SystemNative_PathConf", nullptr}, + {0x690c4347972024f, "AndroidCryptoNative_Aes256Gcm", nullptr}, + {0x6a1f4deffa02c30, "SystemNative_LowLevelMonitor_Acquire", nullptr}, + {0x7b5579ab0499b1f, "AndroidCryptoNative_RsaSize", nullptr}, + {0x7ce8a9b967dd269, "SystemNative_Read", nullptr}, + {0x7f0e1227c9c0225, "CryptoNative_EvpMdCtxDestroy", nullptr}, + {0x8352ae4bba2b83b, "SystemNative_SetSendTimeout", nullptr}, + {0x98bd27a7461321d, "SystemNative_Dup", nullptr}, + {0x9a39fbf59eed9f9, "CryptoNative_EvpSha1", nullptr}, + {0xa4aeeaff9ca2d10, "BrotliDecoderDecompressStream", nullptr}, + {0xa906c14ca5834bc, "SystemNative_GetEUid", nullptr}, + {0xac9f9c1abb62a92, "SystemNative_Log", nullptr}, + {0xadb2441bcfcdfe9, "SystemNative_CreateThread", nullptr}, + {0xafbf5c69d1badc0, "SystemNative_SetTerminalInvalidationHandler", nullptr}, + {0xba897b7abe67b16, "SystemNative_FcntlSetPipeSz", nullptr}, + {0xc305c22ce7ab8a0, "SystemNative_SetSockOpt", nullptr}, + {0xc79e924361c15ca, "SystemNative_RealPath", nullptr}, + {0xcaba893801c6a6f, "AndroidCryptoNative_Aes256Ecb", nullptr}, + {0xcbe6d3d22131194, "AndroidCryptoNative_SetRsaParameters", nullptr}, + {0xe7e93cf9237e1f2, "GlobalizationNative_ToAscii", nullptr}, + {0xef8dd67e25bac53, "SystemNative_GetWindowSize", nullptr}, + {0xfa0899cf8d00a87, "SystemNative_MkDir", nullptr}, + {0xfe7079441ac127e, "SystemNative_CreateSocketEventPort", nullptr}, + {0x1027786cdd9a3e9c, "AndroidCryptoNative_Aes192Cbc", nullptr}, + {0x10d733abd1fd94bb, "SystemNative_TryChangeSocketEventRegistration", nullptr}, + {0x114b8384553f5418, "SystemNative_GetSystemTimeAsTicks", nullptr}, + {0x119a38c3e288a233, "SystemNative_SNPrintF_1S", nullptr}, + {0x11b6f4f0aafeda95, "SystemNative_LowLevelMonitor_TimedWait", nullptr}, + {0x11cc73f2926d4064, "SystemNative_ConfigureTerminalForChildProcess", nullptr}, + {0x121bc483ac26f5f8, "SystemNative_GetGroupName", nullptr}, + {0x12d65f9f65b01497, "SystemNative_GetRawSockOpt", nullptr}, + {0x12eaf09505dc19fd, "SystemNative_FStat", nullptr}, + {0x13577369f5ec4b0a, "SystemNative_GetActiveTcpConnectionInfos", nullptr}, + {0x1399413d8a7d9dd8, "SystemNative_GetAddressFamily", nullptr}, + {0x13a1c2de7fb2519f, "SystemNative_CloseSocketEventPort", nullptr}, + {0x146cd1dc4fb2ba58, "SystemNative_LChflagsCanSetHiddenFlag", nullptr}, + {0x14b7e3527b60e83f, "CryptoNative_ErrErrorStringN", nullptr}, + {0x15bd710d3a9b3b0c, "CryptoNative_EvpDigestFinalEx", nullptr}, + {0x176e22ea7c580dae, "SystemNative_ReadDirR", nullptr}, + {0x18580a4592ed1ea6, "GlobalizationNative_GetSortKey", nullptr}, + {0x185f5d25252c3c72, "SystemNative_FAllocate", nullptr}, + {0x18d6b5e9fec9b0dc, "SystemNative_Connectx", nullptr}, + {0x18f7da5f584b5b59, "SystemNative_PReadV", nullptr}, + {0x1948a0cf88329c2f, "SystemNative_HandleNonCanceledPosixSignal", nullptr}, + {0x1ac95b02f23933cc, "SystemNative_CanGetHiddenFlag", nullptr}, + {0x1d1bb0528d517729, "AndroidCryptoNative_SSLGetSupportedProtocols", nullptr}, + {0x1d4dcbc06728e689, "SystemNative_Close", nullptr}, + {0x1d6d4278ffbbab77, "SystemNative_Pipe", nullptr}, + {0x1d8d6a688fc5bfb3, "SystemNative_SendFile", nullptr}, + {0x1e6228e955989698, "AndroidCryptoNative_EcKeyCreateByOid", nullptr}, + {0x1e8edcc515cd23f9, "CryptoNative_EvpDigestOneShot", nullptr}, + {0x1f1c61a157636aad, "SystemNative_Stat", nullptr}, + {0x1f45ac9d3c6b1554, "AndroidCryptoNative_SSLStreamGetCipherSuite", nullptr}, + {0x1f72f52873ced9c9, "GlobalizationNative_InitOrdinalCasingPage", nullptr}, + {0x1f7d2360a1cdcbff, "AndroidCryptoNative_SSLStreamCreate", nullptr}, + {0x1f849e45a3014a9f, "SystemNative_GetIPv6Address", nullptr}, + {0x1f9361fc7b624c1b, "SystemNative_LowLevelMonitor_Wait", nullptr}, + {0x205a31e661496019, "CryptoNative_ErrGetErrorAlloc", nullptr}, + {0x20784dcc7e9cee75, "BrotliGetTransforms", nullptr}, + {0x2178ba302d0c5f1c, "GlobalizationNative_GetCalendars", nullptr}, + {0x218fce505a140c55, "AndroidCryptoNative_EcDsaVerify", nullptr}, + {0x2291e0ba4e1b55b0, "SystemNative_LStat", nullptr}, + {0x23ac2a4c4d1c744e, "AndroidCryptoNative_X509ChainGetCertificateCount", nullptr}, + {0x24f840f903a26ded, "SystemNative_ConvertErrorPalToPlatform", nullptr}, + {0x24ff74e427d0626e, "SystemNative_GetErrNo", nullptr}, + {0x254905036a0061cf, "SystemNative_CreateSocketEventBuffer", nullptr}, + {0x255c4a2e297fd9f5, "SystemNative_INotifyAddWatch", nullptr}, + {0x267c94097a3bf1f3, "AndroidCryptoNative_CipherDestroy", nullptr}, + {0x27944922cd8283ca, "CryptoNative_EvpSha384", nullptr}, + {0x2795a01c2c64aea1, "CryptoNative_HmacReset", nullptr}, + {0x27f3d9266af2b315, "SystemNative_GetIPv4Address", nullptr}, + {0x2925953889c48cab, "SystemNative_CreateNetworkChangeListenerSocket", nullptr}, + {0x2a49948ae20571cb, "SystemNative_SchedGetAffinity", nullptr}, + {0x2b45d7cdf6e8e0c7, "AndroidCryptoNative_X509StoreDeleteEntry", nullptr}, + {0x2c352dd7c367e438, "CryptoNative_EvpSha512", nullptr}, + {0x2c7e5e179cc917cb, "AndroidCryptoNative_DsaSizeSignature", nullptr}, + {0x2c8da1192c5d7d2b, "SystemNative_FLock", nullptr}, + {0x2d64b1ac218cf29e, "SystemNative_AlignedRealloc", nullptr}, + {0x2e1102c297588e10, "BrotliEncoderDestroyInstance", nullptr}, + {0x2e429d96a9fc92bd, "SystemNative_InitializeTerminalAndSignalHandling", nullptr}, + {0x2fdcf708ff792105, "AndroidCryptoNative_SSLStreamVerifyHostname", nullptr}, + {0x301c465c1ac0adf9, "SystemNative_MProtect", nullptr}, + {0x307db94ae9f929e5, "CryptoNative_GetMaxMdSize", nullptr}, + {0x31027564deeb71b0, "AndroidCryptoNative_Aes128Cbc", nullptr}, + {0x32e594690358a960, "GlobalizationNative_GetLocaleInfoString", nullptr}, + {0x3319a5483b3cc1fc, "SystemNative_GetRLimit", nullptr}, + {0x3424ffcb69ecef57, "SystemNative_Unlink", nullptr}, + {0x346a9bb11364833c, "SystemNative_DrainAutoreleasePool", nullptr}, + {0x35169e67cc0f8529, "SystemNative_GetIPv6MulticastOption", nullptr}, + {0x359205b4a10fa780, "SystemNative_LowLevelMonitor_Destroy", nullptr}, + {0x35c1fa8dffcbbd8c, "CryptoNative_EvpDigestReset", nullptr}, + {0x36128eed665b1923, "SystemNative_ShmUnlink", nullptr}, + {0x364dcf65ae63adff, "SystemNative_GetSocketErrorOption", nullptr}, + {0x3757b327944abb54, "SystemNative_EnablePosixSignalHandling", nullptr}, + {0x38b4bd21127ceffd, "SystemNative_StrErrorR", nullptr}, + {0x38c7de719e8ae69d, "SystemNative_RmDir", nullptr}, + {0x391bbbb9bbde4455, "SystemNative_SetIPv4MulticastOption", nullptr}, + {0x3a7245f3ea476bf7, "SystemNative_SNPrintF", nullptr}, + {0x3ae92e4198427b0d, "SystemNative_ReadLink", nullptr}, + {0x3e0de839e6cfa6e5, "SystemNative_Accept", nullptr}, + {0x3e7cf9a4789a31c7, "SystemNative_FChflags", nullptr}, + {0x3f19a16a3230b551, "AndroidCryptoNative_ChaCha20Poly1305", nullptr}, + {0x3f49b6278f04ae84, "SystemNative_Disconnect", nullptr}, + {0x3fba15600bf0f229, "SystemNative_SetEUid", nullptr}, + {0x401935ffc3454bb1, "AndroidCryptoNative_X509PublicKey", nullptr}, + {0x403e1bc0b3baba84, "CompressionNative_Inflate", nullptr}, + {0x40bfa1211f5f6f9c, "AndroidCryptoNative_EcKeyGetCurveName", nullptr}, + {0x40d61d78487edb08, "GlobalizationNative_GetICUVersion", nullptr}, + {0x41b6e7f32da99fa9, "AndroidCryptoNative_X509ChainDestroyContext", nullptr}, + {0x41c169fb0e30a390, "AndroidCryptoNative_X509ChainGetErrorCount", nullptr}, + {0x41c1f2c9153639af, "SystemNative_FUTimens", nullptr}, + {0x420718c398131a55, "AndroidCryptoNative_SSLStreamGetProtocol", nullptr}, + {0x42339dd2717504d9, "SystemNative_GetLingerOption", nullptr}, + {0x42783107bf2935ec, "SystemNative_FreeHostEntry", nullptr}, + {0x42eb0578a9d62b78, "SystemNative_GetFormatInfoForMountPoint", nullptr}, + {0x4360eb8a25122eee, "GlobalizationNative_StartsWith", nullptr}, + {0x43741165a5ba60d5, "AndroidCryptoNative_CipherUpdateAAD", nullptr}, + {0x44ccb27979f980ce, "SystemNative_AlignedAlloc", nullptr}, + {0x44f1a5c46033eec2, "SystemNative_SysLog", nullptr}, + {0x469898c8d892af83, "BrotliEncoderCompress", nullptr}, + {0x483b434d7b089c7e, "SystemNative_Write", nullptr}, + {0x4845e1c76265acc9, "AndroidCryptoNative_X509StoreEnumerateCertificates", nullptr}, + {0x484a3a445bdb14fc, "SystemNative_GetOSArchitecture", nullptr}, + {0x4909639a9d87bdb5, "SystemNative_AlignedFree", nullptr}, + {0x49e3ba95feb79c6c, "SystemNative_SetAddressFamily", nullptr}, + {0x4a7272ac9d117f2d, "AndroidCryptoNative_EcKeyDestroy", nullptr}, + {0x4b00795bbeea6f60, "SystemNative_SetIPv6Address", nullptr}, + {0x4bd4b1c0803c8c55, "GlobalizationNative_GetLocaleName", nullptr}, + {0x4be7ceca50f3298c, "SystemNative_LowLevelMonitor_Create", nullptr}, + {0x4bec4a1d7dfd4cf7, "SystemNative_GetUnixRelease", nullptr}, + {0x4bfff22801b209ca, "SystemNative_LChflags", nullptr}, + {0x4c22cc4f2b1dab26, "SystemNative_SetPriority", nullptr}, + {0x4c5d96426f92c29d, "CryptoNative_HmacUpdate", nullptr}, + {0x4d6361e5095cff36, "AndroidCryptoNative_DsaSign", nullptr}, + {0x4d74053b37e582fa, "AndroidCryptoNative_X509ChainCreateContext", nullptr}, + {0x4f22643b9509cc12, "GlobalizationNative_IsNormalized", nullptr}, + {0x501daf7e3a890220, "AndroidCryptoNative_X509ChainBuild", nullptr}, + {0x507983f11ffec7a8, "GlobalizationNative_GetTimeZoneDisplayName", nullptr}, + {0x509ff12da4e77259, "SystemNative_GetSocketAddressSizes", nullptr}, + {0x523240c01d14ad50, "SystemNative_GetPeerID", nullptr}, + {0x52794f1118d32f08, "SystemNative_GetUnixVersion", nullptr}, + {0x52fc107ebdb6fcc7, "AndroidCryptoNative_X509StoreRemoveCertificate", nullptr}, + {0x5381564d2c06c0a3, "SystemNative_SysConf", nullptr}, + {0x54ec3421ab70a40a, "Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate", nullptr}, + {0x556bc89d2d4dfc85, "SystemNative_GetDeviceIdentifiers", nullptr}, + {0x558250d199e906bb, "CryptoNative_ErrReasonErrorString", nullptr}, + {0x5592a052ceb4caf6, "SystemNative_GetProcessPath", nullptr}, + {0x55fe2620f63d83d8, "SystemNative_SetDelayedSigChildConsoleConfigurationHandler", nullptr}, + {0x56e982948d00f10d, "GlobalizationNative_IndexOf", nullptr}, + {0x574d77a68ec3e488, "SystemNative_GetEnv", nullptr}, + {0x5755d1cd0c158620, "BrotliDecoderSetParameter", nullptr}, + {0x580dda20ac9e83c6, "BrotliEncoderSetParameter", nullptr}, + {0x583db0344a1cd715, "SystemNative_GetActiveUdpListeners", nullptr}, + {0x5908581fe73717f0, "SystemNative_InterfaceNameToIndex", nullptr}, + {0x5916efc3e1e49137, "CryptoNative_ErrPeekError", nullptr}, + {0x5a114024ecd1162c, "CryptoNative_EvpDigestUpdate", nullptr}, + {0x5a305cf2a314d6a6, "SystemNative_FTruncate", nullptr}, + {0x5a337d9cc7d8bcfd, "CryptoNative_HmacCurrent", nullptr}, + {0x5d503db70d17dad2, "BrotliEncoderIsFinished", nullptr}, + {0x5dd1d1d024378765, "CryptoNative_EvpMdSize", nullptr}, + {0x5e53b688fede3216, "SystemNative_GetControlCharacters", nullptr}, + {0x5fa62856bdbba9c0, "SystemNative_GetPort", nullptr}, + {0x5fd29ac523ff6e3d, "AndroidCryptoNative_SSLStreamRelease", nullptr}, + {0x5ffae3c8023a80b8, "AndroidCryptoNative_SSLStreamGetPeerCertificate", nullptr}, + {0x600b4418896f7808, "SystemNative_Exit", nullptr}, + {0x6089f0c8112eb3d9, "SystemNative_InitializeConsoleBeforeRead", nullptr}, + {0x613307e537d462db, "SystemNative_GetReadDirRBufferSize", nullptr}, + {0x61bacd7170fd8c9b, "SystemNative_SchedSetAffinity", nullptr}, + {0x61f3ce1b18b20d6f, "SystemNative_GetNativeIPInterfaceStatistics", nullptr}, + {0x62351df42d842942, "SystemNative_GetSignalForBreak", nullptr}, + {0x635327a9b09a910d, "GlobalizationNative_NormalizeString", nullptr}, + {0x6393d30aceaa6df2, "SystemNative_PWriteV", nullptr}, + {0x6448f0806bd3a338, "SystemNative_FreeEnviron", nullptr}, + {0x648a9b317bc64fe0, "AndroidCryptoNative_RsaGenerateKeyEx", nullptr}, + {0x650eddee76c6b8da, "SystemNative_GetHostName", nullptr}, + {0x652badfba5d61929, "SystemNative_FcntlSetFD", nullptr}, + {0x66e049fe27bf91ea, "AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration", nullptr}, + {0x6792c0a7ea5d19c9, "BrotliEncoderTakeOutput", nullptr}, + {0x67a8868ef592a3fd, "AndroidCryptoNative_SSLStreamShutdown", nullptr}, + {0x67a9b5bbce322f8c, "AndroidCryptoNative_Des3Cbc", nullptr}, + {0x67d2cd86792b1d0c, "SystemNative_Realloc", nullptr}, + {0x67e9d60481f4be06, "SystemNative_PlatformSupportsDualModeIPv4PacketInfo", nullptr}, + {0x68df81a8fb5bf442, "SystemNative_GetSockOpt", nullptr}, + {0x68f3fe6083c0355b, "SystemNative_GetLoadLibraryError", nullptr}, + {0x69ad99fac0467f64, "SystemNative_Link", nullptr}, + {0x6a59d9242cd31785, "AndroidCryptoNative_RsaPrivateDecrypt", nullptr}, + {0x6ac3aeecfc75bfad, "GlobalizationNative_GetSortVersion", nullptr}, + {0x6b9097385aa77917, "SystemNative_FSync", nullptr}, + {0x6b9bce16ba8e845f, "SystemNative_Malloc", nullptr}, + {0x6bc18fbbbf267e2a, "SystemNative_ReceiveSocketError", nullptr}, + {0x6d566e1f6e5a2d8f, "BrotliDefaultAllocFunc", nullptr}, + {0x6dbd90e9cc86310b, "AndroidCryptoNative_CipherFinalEx", nullptr}, + {0x6dfd40c2dd0d7382, "AndroidCryptoNative_RsaUpRef", nullptr}, + {0x6e2c1caff08e6e2d, "SystemNative_ReadStdin", nullptr}, + {0x6ee05d5e8650e56c, "SystemNative_DisablePosixSignalHandling", nullptr}, + {0x6f990f1f7bc80630, "AndroidCryptoNative_RsaCreate", nullptr}, + {0x70f907b97d3fe059, "AndroidCryptoNative_Aes192Ccm", nullptr}, + {0x7150f0eb40797bb3, "AndroidCryptoNative_SSLStreamCreateWithCertificates", nullptr}, + {0x724820d307055ed1, "CryptoNative_HmacFinal", nullptr}, + {0x729afe37cdb8ae8f, "SystemNative_Connect", nullptr}, + {0x730ae9a7469a7321, "SystemNative_GetAllMountPoints", nullptr}, + {0x7356b141407d261e, "AndroidCryptoNative_EcdhDeriveKey", nullptr}, + {0x742da00b2dbf435d, "SystemNative_LoadLibrary", nullptr}, + {0x74ec4a8d869776ad, "AndroidCryptoNative_Aes128Ccm", nullptr}, + {0x7559feb379d38da5, "SystemNative_GetTimeZoneData", nullptr}, + {0x758dfbf057da0da0, "AndroidCryptoNative_DsaSignatureFieldSize", nullptr}, + {0x77ca6a148e5a51d9, "GlobalizationNative_IanaIdToWindowsId", nullptr}, + {0x7975d1d7029cf1a3, "AndroidCryptoNative_Aes128Gcm", nullptr}, + {0x79f5c24afbd04af1, "AndroidCryptoNative_Aes256Cbc", nullptr}, + {0x7a37e0d077f2dfe5, "AndroidCryptoNative_DsaGenerateKey", nullptr}, + {0x7a4d912694906c9c, "GlobalizationNative_ToUnicode", nullptr}, + {0x7af1f52a7a632e95, "BrotliDecoderTakeOutput", nullptr}, + {0x7d5273ad530e7298, "AndroidCryptoNative_X509StoreOpenDefault", nullptr}, + {0x7d7ee4bce74d4de9, "SystemNative_GetDomainSocketSizes", nullptr}, + {0x7e1766c6df3ad261, "SystemNative_MUnmap", nullptr}, + {0x7e4bdf46d4ff9f11, "SystemNative_MkNod", nullptr}, + {0x7e5fa2f70891c7fe, "GlobalizationNative_ChangeCaseTurkish", nullptr}, + {0x7ec328b6ba9eab8a, "SystemNative_WaitForSocketEvents", nullptr}, + {0x7fa96d0284954375, "AndroidCryptoNative_X509Decode", nullptr}, + {0x80ef5040fdcc248d, "BrotliEncoderMaxCompressedSize", nullptr}, + {0x813bedf08c3388d4, "AndroidCryptoNative_Aes128Cfb8", nullptr}, + {0x84c8a7489b37fea0, "SystemNative_GetPlatformSignalNumber", nullptr}, + {0x84cc0301870c37ce, "AndroidCryptoNative_SSLStreamSetTargetHost", nullptr}, + {0x8502eeba98158e79, "SystemNative_FcntlSetIsNonBlocking", nullptr}, + {0x8530d37777969db6, "SystemNative_SetKeypadXmit", nullptr}, + {0x85d0033bc38bb4bb, "SystemNative_MAdvise", nullptr}, + {0x868e09dc7dfea364, "AndroidCryptoNative_RsaSignPrimitive", nullptr}, + {0x870191ad244b8069, "AndroidCryptoNative_RegisterRemoteCertificateValidationCallback", nullptr}, + {0x87019b7831c0c34c, "AndroidCryptoNative_Aes192Gcm", nullptr}, + {0x87c447e7f873cff0, "AndroidCryptoNative_X509ChainValidate", nullptr}, + {0x889350f209555ecb, "SystemNative_MkdTemp", nullptr}, + {0x88a08b60b80c70cc, "SystemNative_FChMod", nullptr}, + {0x88cfeefc903f9d60, "CryptoNative_EvpDigestCurrent", nullptr}, + {0x8bcabce135063bed, "SystemNative_OpenDir", nullptr}, + {0x8df448aee6e8fa5e, "SystemNative_WaitPidExitedNoHang", nullptr}, + {0x8e96cb02418947cc, "SystemNative_FcntlGetPipeSz", nullptr}, + {0x8fb6ed14ee0256bc, "SystemNative_GetTimestamp", nullptr}, + {0x8ffe2d950d138c01, "SystemNative_SchedGetCpu", nullptr}, + {0x9039632237d70ae7, "AndroidCryptoNative_NewGlobalReference", nullptr}, + {0x9161ade1206fd86e, "AndroidCryptoNative_Aes256Cfb128", nullptr}, + {0x9167a072639a7c95, "AndroidCryptoNative_Aes256Ccm", nullptr}, + {0x91f065ec0d3aec55, "AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey", nullptr}, + {0x93a8bec488055608, "SystemNative_GetPwNamR", nullptr}, + {0x95a0e2fc5c0cb49e, "AndroidCryptoNative_SSLStreamSetApplicationProtocols", nullptr}, + {0x95a4cb8563cc6b14, "SystemNative_ShmOpen", nullptr}, + {0x9856fa59ed936b73, "SystemNative_GetSid", nullptr}, + {0x996ada1c038aabba, "SystemNative_MksTemps", nullptr}, + {0x9991a277809ef205, "AndroidCryptoNative_SSLStreamGetApplicationProtocol", nullptr}, + {0x99a840c495204202, "SystemNative_GetBytesAvailable", nullptr}, + {0x99e3660fc483d7be, "CryptoNative_GetRandomBytes", nullptr}, + {0x9aa9eaee3dd8b23b, "SystemNative_GetIPv4MulticastOption", nullptr}, + {0x9aaaad33b28af82f, "SystemNative_SetSignalForBreak", nullptr}, + {0x9aab07f824659d3e, "AndroidCryptoNative_DsaKeyCreateByExplicitParameters", nullptr}, + {0x9c3e8b890033819a, "SystemNative_FcntlCanGetSetPipeSz", nullptr}, + {0x9c832cd7fcbf2de0, "SystemNative_MkFifo", nullptr}, + {0x9d2cb31282abd3d9, "SystemNative_GetNetworkInterfaces", nullptr}, + {0x9e25ebf4f61cc299, "SystemNative_ChDir", nullptr}, + {0x9e79166979634030, "AndroidCryptoNative_CipherSetKeyAndIV", nullptr}, + {0x9edddf30d660eff4, "AndroidCryptoNative_Aes192Ecb", nullptr}, + {0x9fb01da1222e905a, "SystemNative_IsATty", nullptr}, + {0xa193402ff5140ac1, "GlobalizationNative_GetCalendarInfo", nullptr}, + {0xa1e881a63614507e, "SystemNative_INotifyRemoveWatch", nullptr}, + {0xa2254fea4d8b6909, "SystemNative_MMap", nullptr}, + {0xa272b5349013d9ef, "CryptoNative_EvpSha256", nullptr}, + {0xa2d7790a850024c0, "SystemNative_GetNumRoutes", nullptr}, + {0xa302613a430248b8, "SystemNative_GetGroups", nullptr}, + {0xa308025a784497df, "AndroidCryptoNative_SSLStreamSetEnabledProtocols", nullptr}, + {0xa56532a23755cd87, "SystemNative_StdinReady", nullptr}, + {0xa56954e28eb9a9c9, "AndroidCryptoNative_Des3Cfb8", nullptr}, + {0xa57e18f82abd5958, "BrotliDecoderDestroyInstance", nullptr}, + {0xa5eda72b95fe78c3, "AndroidCryptoNative_X509ChainGetErrors", nullptr}, + {0xa831a683f743e417, "GlobalizationNative_WindowsIdToIanaId", nullptr}, + {0xa89b70c38d3ba079, "CryptoNative_HmacCreate", nullptr}, + {0xa89ec9958d999483, "SystemNative_GetCwd", nullptr}, + {0xa8bdc3e7ee898dfc, "SystemNative_Shutdown", nullptr}, + {0xa93eb533acf7564d, "AndroidCryptoNative_DesEcb", nullptr}, + {0xa94b1cf083978da9, "CryptoNative_EvpMdCtxCopyEx", nullptr}, + {0xa961e8db31830e16, "AndroidCryptoNative_Aes192Cfb8", nullptr}, + {0xaa8f0f87ae474ffe, "AndroidCryptoNative_SSLStreamCreateWithKeyStorePrivateKeyEntry", nullptr}, + {0xabdcf2f74d210f35, "SystemNative_GetCryptographicallySecureRandomBytes", nullptr}, + {0xac11eab9d9c31b01, "SystemNative_UTimensat", nullptr}, + {0xac5c6a70d140a4bf, "GlobalizationNative_GetLocaleTimeFormat", nullptr}, + {0xac7725c652a5fb5b, "SystemNative_CopyFile", nullptr}, + {0xad1a2d6575cdd4e3, "AndroidCryptoNative_SSLStreamWrite", nullptr}, + {0xad228cdc4edb11d6, "SystemNative_CloseDir", nullptr}, + {0xadc6889903a2d6f4, "SystemNative_Rename", nullptr}, + {0xae320903718eb45d, "SystemNative_MapTcpState", nullptr}, + {0xae82e9ceae24192d, "AndroidCryptoNative_Pbkdf2", nullptr}, + {0xaf72b94c4acee897, "BrotliDecoderHasMoreOutput", nullptr}, + {0xaf9706efc72c3904, "SystemNative_SetIPv6MulticastOption", nullptr}, + {0xafd9f6338cdbadd4, "SystemNative_GetHostEntryForName", nullptr}, + {0xafe3d21bbaa71464, "CompressionNative_DeflateEnd", nullptr}, + {0xb0b66a7145de350d, "SystemNative_Access", nullptr}, + {0xb0df46ff09c57741, "AndroidCryptoNative_GetRsaParameters", nullptr}, + {0xb0e18377ed603e0b, "SystemNative_GetGroupList", nullptr}, + {0xb1c394b9992bd67d, "AndroidCryptoNative_EcDsaSign", nullptr}, + {0xb1ff12f3bd735982, "AndroidCryptoNative_AeadCipherFinalEx", nullptr}, + {0xb361006446f560e8, "SystemNative_LogError", nullptr}, + {0xb3e1e5e50cde576e, "BrotliEncoderVersion", nullptr}, + {0xb41fa43cc5c261cb, "BrotliDecoderGetErrorCode", nullptr}, + {0xb4996dd1aba38200, "AndroidCryptoNative_EcDsaSize", nullptr}, + {0xb516027cb59e6541, "BrotliDecoderIsFinished", nullptr}, + {0xb575ec01a7a79f8f, "AndroidCryptoNative_DesCfb8", nullptr}, + {0xb600c44028c1743d, "SystemNative_Socket", nullptr}, + {0xb632e9bc6f7be0a9, "SystemNative_GetSockName", nullptr}, + {0xb6540b73eff28747, "SystemNative_SetRawSockOpt", nullptr}, + {0xb66be1550d27bfb4, "AndroidCryptoNative_GetECCurveParameters", nullptr}, + {0xb69c3cc8b9f6a724, "BrotliDecoderIsUsed", nullptr}, + {0xb6ab9abf7887911f, "SystemNative_ReadEvents", nullptr}, + {0xb73c597de01bc0b2, "SystemNative_GetPwUidR", nullptr}, + {0xb78af5975603cd20, "SystemNative_Sync", nullptr}, + {0xb7bbbe2c16a565c6, "SystemNative_Calloc", nullptr}, + {0xb81236cd1fe85cc9, "GlobalizationNative_GetLatestJapaneseEra", nullptr}, + {0xb828d9e7df5437a5, "BrotliDecoderErrorString", nullptr}, + {0xb95350c7ec77bc72, "GlobalizationNative_ChangeCase", nullptr}, + {0xba2f6d298f3be8bc, "CryptoNative_EvpMd5", nullptr}, + {0xbb3343826d504870, "SystemNative_GetBootTimeTicks", nullptr}, + {0xbb5e970ecb6745da, "SystemNative_SymLink", nullptr}, + {0xbbd20cce92ec2c12, "SystemNative_FcntlGetFD", nullptr}, + {0xbcd9e53d2d288094, "SystemNative_GetNameInfo", nullptr}, + {0xbd5a0be2f7904089, "AndroidCryptoNative_X509StoreAddCertificate", nullptr}, + {0xbd89ef4df5486744, "SystemNative_Send", nullptr}, + {0xbdbbd2898347c0d1, "AndroidCryptoNative_SSLStreamHandshake", nullptr}, + {0xbdd3128e77381b01, "SystemNative_EnumerateInterfaceAddresses", nullptr}, + {0xbe8df478de07c6d8, "BrotliDefaultFreeFunc", nullptr}, + {0xc00ebc097b776c1f, "SystemNative_GetPriority", nullptr}, + {0xc036b23d88fad91b, "SystemNative_iOSSupportVersion", nullptr}, + {0xc0bb2dd0c5b74436, "CryptoNative_EnsureOpenSslInitialized", nullptr}, + {0xc10e411c989a9314, "CompressionNative_Deflate", nullptr}, + {0xc11cd661db8be230, "AndroidCryptoNative_Des3Cfb64", nullptr}, + {0xc183a0550feea0d6, "BrotliEncoderCompressStream", nullptr}, + {0xc19b94823ea1d39e, "CryptoNative_HmacOneShot", nullptr}, + {0xc1b8a5f1c799e4bb, "BrotliGetDictionary", nullptr}, + {0xc1c679eefc134d31, "SystemNative_LowLevelMonitor_Release", nullptr}, + {0xc287daf58054a21d, "GlobalizationNative_EndsWith", nullptr}, + {0xc2d5e1c465b2f5b6, "AndroidCryptoNative_DsaSizeP", nullptr}, + {0xc3145e336c38379b, "AndroidCryptoNative_SSLStreamGetPeerCertificates", nullptr}, + {0xc3c10021b10ba455, "SystemNative_GetEGid", nullptr}, + {0xc3fe9394fe1f3f02, "SystemNative_GetSocketType", nullptr}, + {0xc560d9947ab2a34d, "SystemNative_RegisterForSigChld", nullptr}, + {0xc5bed971846027de, "SystemNative_GetCpuUtilization", nullptr}, + {0xc69433678dd341ca, "SystemNative_ForkAndExecProcess", nullptr}, + {0xc7815e0476511544, "AndroidCryptoNative_X509Encode", nullptr}, + {0xc7ae1b8d93af5d73, "SystemNative_ChMod", nullptr}, + {0xc7d536c0e7eb3fe2, "SystemNative_FreeSocketEventBuffer", nullptr}, + {0xc7f81d5b58b65ac0, "BrotliEncoderCreateInstance", nullptr}, + {0xc87a5ee4869035c6, "SystemNative_UninitializeConsoleAfterRead", nullptr}, + {0xc8a52a8b6d96b32b, "AndroidCryptoNative_X509ExportPkcs7", nullptr}, + {0xc8b772178f955d87, "GlobalizationNative_GetSortHandle", nullptr}, + {0xc93df58ae5457bfd, "SystemNative_GetControlMessageBufferSize", nullptr}, + {0xc956e528f995739c, "SystemNative_ReceiveMessage", nullptr}, + {0xca001af79c0d7a8b, "CompressionNative_InflateEnd", nullptr}, + {0xca48c3927c202794, "AndroidCryptoNative_GetECKeyParameters", nullptr}, + {0xcaae6d345ba32c7b, "SystemNative_Kill", nullptr}, + {0xcaec08aa13779f7f, "SystemNative_GetEnviron", nullptr}, + {0xcaf599a20538b10b, "SystemNative_SetWindowSize", nullptr}, + {0xcb4bcdafdc81d116, "AndroidCryptoNative_CipherCreatePartial", nullptr}, + {0xcbbb90469d28cded, "SystemNative_SearchPath", nullptr}, + {0xcc433093c073719e, "AndroidCryptoNative_SSLStreamRead", nullptr}, + {0xcc43d880192dd6ff, "SystemNative_ConvertErrorPlatformToPal", nullptr}, + {0xcc788c0474c3e178, "SystemNative_LSeek", nullptr}, + {0xcd5d8a63493f5e38, "CompressionNative_InflateInit2_", nullptr}, + {0xcdcb014df9a6eae2, "SystemNative_SetPort", nullptr}, + {0xce36e2e1a139a020, "SystemNative_GetDefaultTimeZone", nullptr}, + {0xce6ddfe40fed99d9, "SystemNative_PRead", nullptr}, + {0xce9f8a6ac705faa5, "AndroidCryptoNative_X509DecodeCollection", nullptr}, + {0xceba527295694651, "BrotliDecoderCreateInstance", nullptr}, + {0xd0899515dfe85287, "GlobalizationNative_LoadICU", nullptr}, + {0xd185dfe303ab91dd, "GlobalizationNative_CompareString", nullptr}, + {0xd392d6ed5dcc111c, "SystemNative_GetDomainName", nullptr}, + {0xd5264d57a926edfb, "GlobalizationNative_InitICUFunctions", nullptr}, + {0xd55437b16dc84f3b, "SystemNative_GetIPv4GlobalStatistics", nullptr}, + {0xd5c063a90ae882c1, "AndroidCryptoNative_CipherIsSupported", nullptr}, + {0xd7d818c7640598dc, "AndroidCryptoNative_X509ChainGetCertificates", nullptr}, + {0xd7f1a8f616897ace, "AndroidCryptoNative_Aes256Cfb8", nullptr}, + {0xd88be8f9e9f28e90, "SystemNative_GetIcmpv4GlobalStatistics", nullptr}, + {0xd8976692c4c68818, "SystemNative_GetEstimatedUdpListenerCount", nullptr}, + {0xd8a9e47b6ca78448, "CryptoNative_ErrPeekLastError", nullptr}, + {0xd995e71361e6ed2e, "GlobalizationNative_IsPredefinedLocale", nullptr}, + {0xd9bd0b370726ce34, "AndroidCryptoNative_CipherReset", nullptr}, + {0xda05c57c78aa6706, "SystemNative_LowLevelMonitor_Signal_Release", nullptr}, + {0xda38bffa1d16cdd6, "SystemNative_SetLingerOption", nullptr}, + {0xda4898a26933f73d, "AndroidCryptoNative_DsaVerify", nullptr}, + {0xda6b3192974ca60e, "SystemNative_Open", nullptr}, + {0xdab5eb45815daabc, "SystemNative_GetAtOutOfBandMark", nullptr}, + {0xdae32aac0c0d305c, "SystemNative_ReadProcessStatusInfo", nullptr}, + {0xdbb4752ed23670f0, "AndroidCryptoNative_DesCbc", nullptr}, + {0xdbee22594fa8c585, "SystemNative_CreateAutoreleasePool", nullptr}, + {0xdc51159ffe70b0e0, "BrotliDecoderVersion", nullptr}, + {0xdc780005b0d39711, "AndroidCryptoNative_X509StoreGetPrivateKeyEntry", nullptr}, + {0xdd4c03f06ce96e04, "AndroidCryptoNative_RsaDestroy", nullptr}, + {0xdde06993f87d6ffc, "AndroidCryptoNative_Aes128Cfb128", nullptr}, + {0xde1e22dd097f799c, "AndroidCryptoNative_CipherSetNonceLength", nullptr}, + {0xde259001bf54e6f1, "AndroidCryptoNative_SSLStreamIsLocalCertificateUsed", nullptr}, + {0xdec5c7544d2c8cb1, "AndroidCryptoNative_GetDsaParameters", nullptr}, + {0xdf650444c8af0763, "SystemNative_FcntlGetIsNonBlocking", nullptr}, + {0xdfede2defd776f7e, "AndroidCryptoNative_X509ChainSetCustomTrustStore", nullptr}, + {0xe059239741e0011a, "AndroidCryptoNative_EcKeyCreateByKeyParameters", nullptr}, + {0xe072da8f2d921f53, "GlobalizationNative_GetDefaultLocaleName", nullptr}, + {0xe0a170d2b947a8fc, "SystemNative_SendMessage", nullptr}, + {0xe0a601fd89d9b279, "SystemNative_SetErrNo", nullptr}, + {0xe0f34ce89fd38aef, "AndroidCryptoNative_RsaPublicEncrypt", nullptr}, + {0xe1930d112ce74c9e, "SystemNative_TryGetUInt32OSThreadId", nullptr}, + {0xe20c29fb8b19da7b, "SystemNative_Listen", nullptr}, + {0xe36a157177b2db08, "SystemNative_GetNonCryptographicallySecureRandomBytes", nullptr}, + {0xe44f737a5bebdd90, "SystemNative_SetIPv4Address", nullptr}, + {0xe582a4a60bb74c35, "SystemNative_GetProcAddress", nullptr}, + {0xe604fca300068c0c, "AndroidCryptoNative_CipherCtxSetPadding", nullptr}, + {0xe6838f2add787bfe, "SystemNative_FreeLibrary", nullptr}, + {0xe73aeaf9e3a10343, "SystemNative_PWrite", nullptr}, + {0xe78ff100d1d73d99, "SystemNative_SetReceiveTimeout", nullptr}, + {0xe853ecfe4d402ed0, "SystemNative_Poll", nullptr}, + {0xea21aa1f2b2a671c, "GlobalizationNative_LastIndexOf", nullptr}, + {0xea5e6653389b924a, "CompressionNative_DeflateInit2_", nullptr}, + {0xea61d6c040267b2d, "BrotliSetDictionaryData", nullptr}, + {0xeaafb7963ceb9bf4, "SystemNative_GetTcpGlobalStatistics", nullptr}, + {0xeab45239fb3f138d, "AndroidCryptoNative_GetBigNumBytes", nullptr}, + {0xec67e4076662c2de, "SystemNative_GetDefaultSearchOrderPseudoHandle", nullptr}, + {0xee4dd111dc8d98f3, "GlobalizationNative_GetJapaneseEraStartDate", nullptr}, + {0xef71ee101b3ece96, "SystemNative_GetIcmpv6GlobalStatistics", nullptr}, + {0xeff5d014640ae969, "AndroidCryptoNative_DeleteGlobalReference", nullptr}, + {0xf0045895a9043221, "SystemNative_SearchPath_TempDirectory", nullptr}, + {0xf0658a22dd5ede19, "SystemNative_SNPrintF_1I", nullptr}, + {0xf0ec052da6c5fa70, "SystemNative_EnumerateGatewayAddressesForInterface", nullptr}, + {0xf1577384f409ea85, "AndroidCryptoNative_BigNumToBinary", nullptr}, + {0xf2c7fa39bf166188, "SystemNative_Free", nullptr}, + {0xf2d074e0aeca51ce, "GlobalizationNative_GetLocales", nullptr}, + {0xf3693f3cadb9b6f4, "GlobalizationNative_EnumCalendarInfo", nullptr}, + {0xf38b47e43f352491, "SystemNative_GetUdpGlobalStatistics", nullptr}, + {0xf432f105a045b088, "CryptoNative_ErrClearError", nullptr}, + {0xf4dea312f71c5ff2, "AndroidCryptoNative_Aes128Ecb", nullptr}, + {0xf4f5526ddc32beac, "CryptoNative_HmacDestroy", nullptr}, + {0xf57f81262f07542c, "AndroidCryptoNative_Des3Ecb", nullptr}, + {0xf63fa2bfce5c4f80, "GlobalizationNative_GetLocaleInfoGroupingSizes", nullptr}, + {0xf6ede5d5d8729315, "SystemNative_WaitIdAnyExitedNoHangNoWait", nullptr}, + {0xf75d4fdd6e749a84, "BrotliTransformDictionaryWord", nullptr}, + {0xf7b334768844b502, "AndroidCryptoNative_X509StoreContainsCertificate", nullptr}, + {0xf85b8ffeba9b06c1, "AndroidCryptoNative_X509StoreEnumerateTrustedCertificates", nullptr}, + {0xf870179a8d8d1872, "SystemNative_PosixFAdvise", nullptr}, + {0xf8c983dd21ef9fe6, "SystemNative_GetPid", nullptr}, + {0xf96bc1e7e15e69f2, "AndroidCryptoNative_CipherUpdate", nullptr}, + {0xf970881d4fa83e07, "AndroidCryptoNative_CipherCreate", nullptr}, + {0xf9c3d216226b3355, "AndroidCryptoNative_CipherSetTagLength", nullptr}, + {0xf9dea6e72f1fffc9, "CryptoNative_EvpMdCtxCreate", nullptr}, + {0xfa21f0a127c9dce9, "GlobalizationNative_ChangeCaseInvariant", nullptr}, + {0xfa2669c25616a8ff, "AndroidCryptoNative_X509IsKeyStorePrivateKeyEntry", nullptr}, + {0xfa26b86cedf66721, "SystemNative_Sysctl", nullptr}, + {0xfaa7766eaa2c54a5, "AndroidCryptoNative_DecodeRsaSubjectPublicKeyInfo", nullptr}, + {0xfacf02f439426705, "GlobalizationNative_CloseSortHandle", nullptr}, + {0xfb3e394cc613f202, "SystemNative_GetPeerName", nullptr}, + {0xfbb57319454b1074, "SystemNative_GetSpaceInfoForMountPoint", nullptr}, + {0xfc0bad2b1528000f, "AndroidCryptoNative_RsaVerificationPrimitive", nullptr}, + {0xfcdeea476953780c, "AndroidCryptoNative_Aes192Cfb128", nullptr}, + {0xfd2cdd99f11de76c, "AndroidCryptoNative_EcKeyGetSize", nullptr}, + {0xfd4f2784ec1c98aa, "AndroidCryptoNative_SSLStreamRequestClientAuthentication", nullptr}, + {0xfe3dd06281f7cd1f, "AndroidCryptoNative_SSLStreamInitialize", nullptr}, + {0xff28b3bec4f32a2c, "SystemNative_GetFileSystemType", nullptr}, + {0xff9b8d95b0e209fb, "BrotliEncoderHasMoreOutput", nullptr}, + {0xffce9341c40b2b73, "BrotliDecoderDecompress", nullptr}, + }}; + + +constexpr hash_t java_interop_library_hash = 0x54568ec36068e6b6; +constexpr hash_t xa_internal_api_library_hash = 0x43fd1b21148361b2; +constexpr hash_t android_liblog_library_hash = 0x1f2e4bce0544fb0a; +constexpr hash_t system_native_library_hash = 0x4cd7bd0032e920e1; +constexpr hash_t system_io_compression_native_library_hash = 0x9190f4cb761b1d3c; +constexpr hash_t system_security_cryptography_native_android_library_hash = 0x1848c0093f0afd8; +constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; +#else + //32-bit internal p/invoke table + std::array internal_pinvokes {{ + {0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast(&monodroid_TypeManager_get_java_class_name)}, + {0x39e5b5d4, "__android_log_print", reinterpret_cast(&__android_log_print)}, + {0x656e00bd, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, + {0xa04e5d1c, "monodroid_free", reinterpret_cast(&monodroid_free)}, + {0xb02468aa, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, + {0xb6431f9a, "clr_typemap_java_to_managed", reinterpret_cast(&clr_typemap_java_to_managed)}, + {0xbe8d7701, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, + {0xc5146c54, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, + {0xe7e77ca5, "_monodroid_gref_log", reinterpret_cast(&_monodroid_gref_log)}, + {0xfa4e32ca, "monodroid_log", reinterpret_cast(&monodroid_log)}, + }}; + + //32-bit DotNet p/invoke table + std::array dotnet_pinvokes {{ + {0xaf6b1c, "AndroidCryptoNative_RsaPrivateDecrypt", nullptr}, + {0x1733089, "SystemNative_SetTerminalInvalidationHandler", nullptr}, + {0x1dd1f00, "AndroidCryptoNative_Aes192Cfb8", nullptr}, + {0x23a0578, "AndroidCryptoNative_NewGlobalReference", nullptr}, + {0x2f05496, "SystemNative_GetPeerName", nullptr}, + {0x3295077, "SystemNative_MapTcpState", nullptr}, + {0x3d9bc5f, "SystemNative_Unlink", nullptr}, + {0x3e12cb4, "SystemNative_INotifyInit", nullptr}, + {0x5b0fb1d, "SystemNative_InitializeConsoleBeforeRead", nullptr}, + {0x80f30b4, "BrotliDecoderTakeOutput", nullptr}, + {0x84ccf89, "SystemNative_MSync", nullptr}, + {0x8c636a2, "SystemNative_FcntlSetPipeSz", nullptr}, + {0x8de5b3d, "SystemNative_GetSid", nullptr}, + {0x92bf2d9, "AndroidCryptoNative_EcKeyGetSize", nullptr}, + {0xaa46d20, "SystemNative_SNPrintF", nullptr}, + {0xaa7c86e, "SystemNative_Exit", nullptr}, + {0xb6a80bd, "SystemNative_SetAddressFamily", nullptr}, + {0xbdd984d, "SystemNative_SetWindowSize", nullptr}, + {0xcc59904, "CryptoNative_HmacDestroy", nullptr}, + {0xd5ca844, "SystemNative_CreateSocketEventPort", nullptr}, + {0xd98d741, "SystemNative_Kill", nullptr}, + {0xdfe3e26, "SystemNative_Connectx", nullptr}, + {0xfc48476, "SystemNative_GetNonCryptographicallySecureRandomBytes", nullptr}, + {0x10d108c9, "SystemNative_FreeHostEntry", nullptr}, + {0x1165644f, "SystemNative_GetOSArchitecture", nullptr}, + {0x11778651, "SystemNative_ConfigureTerminalForChildProcess", nullptr}, + {0x1178ebdd, "CryptoNative_EvpDigestFinalEx", nullptr}, + {0x11a2796d, "SystemNative_GetTcpGlobalStatistics", nullptr}, + {0x11d9981e, "SystemNative_MProtect", nullptr}, + {0x12105897, "GlobalizationNative_NormalizeString", nullptr}, + {0x12b01cc9, "GlobalizationNative_IsNormalized", nullptr}, + {0x12fdf5c3, "SystemNative_ConvertErrorPlatformToPal", nullptr}, + {0x1348bf25, "AndroidCryptoNative_SSLStreamWrite", nullptr}, + {0x1376985b, "SystemNative_SetSockOpt", nullptr}, + {0x13925de2, "SystemNative_GetLingerOption", nullptr}, + {0x13f565a9, "SystemNative_GetControlMessageBufferSize", nullptr}, + {0x142a08a1, "SystemNative_PosixFAdvise", nullptr}, + {0x16d98313, "GlobalizationNative_IndexOf", nullptr}, + {0x17549123, "SystemNative_Connect", nullptr}, + {0x17a5d095, "AndroidCryptoNative_SSLStreamGetApplicationProtocol", nullptr}, + {0x17b96c39, "SystemNative_FreeSocketEventBuffer", nullptr}, + {0x1904820d, "SystemNative_GetHostEntryForName", nullptr}, + {0x19b6a696, "AndroidCryptoNative_X509DecodeCollection", nullptr}, + {0x1a302b28, "SystemNative_SchedSetAffinity", nullptr}, + {0x1aa4105d, "GlobalizationNative_GetSortKey", nullptr}, + {0x1ab1248e, "SystemNative_GetHostName", nullptr}, + {0x1bf277c4, "SystemNative_WaitForSocketEvents", nullptr}, + {0x1c4778bf, "SystemNative_AlignedFree", nullptr}, + {0x1cb466df, "AndroidCryptoNative_RsaGenerateKeyEx", nullptr}, + {0x1cf7b52c, "SystemNative_MAdvise", nullptr}, + {0x1eb6eaaa, "CryptoNative_GetRandomBytes", nullptr}, + {0x1ebc63c1, "AndroidCryptoNative_X509ChainDestroyContext", nullptr}, + {0x1f186646, "AndroidCryptoNative_CipherSetKeyAndIV", nullptr}, + {0x1f1cd573, "AndroidCryptoNative_Des3Cfb64", nullptr}, + {0x1f998744, "AndroidCryptoNative_Aes128Cfb128", nullptr}, + {0x1fdcd1e0, "CryptoNative_ErrPeekError", nullptr}, + {0x212e38c4, "SystemNative_GetUdpGlobalStatistics", nullptr}, + {0x218fa94a, "AndroidCryptoNative_X509StoreDeleteEntry", nullptr}, + {0x22011e2b, "SystemNative_SetLingerOption", nullptr}, + {0x224ebd71, "SystemNative_Listen", nullptr}, + {0x2253b591, "BrotliGetTransforms", nullptr}, + {0x226eec4d, "SystemNative_Abort", nullptr}, + {0x229f73d4, "AndroidCryptoNative_RsaUpRef", nullptr}, + {0x22bbb587, "AndroidCryptoNative_SSLStreamGetPeerCertificate", nullptr}, + {0x2304e65b, "SystemNative_SetRLimit", nullptr}, + {0x23cfcfb0, "BrotliTransformDictionaryWord", nullptr}, + {0x260a3e8d, "CompressionNative_DeflateInit2_", nullptr}, + {0x289b5430, "SystemNative_Log", nullptr}, + {0x28d95a99, "SystemNative_CanGetHiddenFlag", nullptr}, + {0x28f3db4b, "SystemNative_ShmUnlink", nullptr}, + {0x2af6aa40, "SystemNative_Access", nullptr}, + {0x2b117055, "BrotliDecoderDecompress", nullptr}, + {0x2b7293c5, "SystemNative_GetTimestamp", nullptr}, + {0x2b747a9c, "SystemNative_MkNod", nullptr}, + {0x2bc9ff5e, "AndroidCryptoNative_SSLStreamGetProtocol", nullptr}, + {0x2c4415fd, "AndroidCryptoNative_AeadCipherFinalEx", nullptr}, + {0x2c467430, "AndroidCryptoNative_GetECCurveParameters", nullptr}, + {0x2d21ad97, "SystemNative_GetReadDirRBufferSize", nullptr}, + {0x2d6e4a1c, "AndroidCryptoNative_X509StoreRemoveCertificate", nullptr}, + {0x2e66f31b, "BrotliDecoderDestroyInstance", nullptr}, + {0x2eb28fb6, "SystemNative_GetIPv4Address", nullptr}, + {0x2f7d80dd, "GlobalizationNative_WindowsIdToIanaId", nullptr}, + {0x2ff73621, "CryptoNative_ErrReasonErrorString", nullptr}, + {0x30af09b7, "AndroidCryptoNative_DecodeRsaSubjectPublicKeyInfo", nullptr}, + {0x31120969, "SystemNative_Malloc", nullptr}, + {0x3374b950, "SystemNative_GetLoadLibraryError", nullptr}, + {0x34867c2f, "SystemNative_TryGetUInt32OSThreadId", nullptr}, + {0x349c5a8f, "SystemNative_GetNetworkInterfaces", nullptr}, + {0x354aa58f, "AndroidCryptoNative_DsaKeyCreateByExplicitParameters", nullptr}, + {0x363c0010, "CryptoNative_EvpDigestUpdate", nullptr}, + {0x367eee31, "AndroidCryptoNative_SSLStreamIsLocalCertificateUsed", nullptr}, + {0x38406fa3, "GlobalizationNative_ChangeCaseInvariant", nullptr}, + {0x38575bc5, "SystemNative_GetUnixRelease", nullptr}, + {0x388a31d4, "SystemNative_PathConf", nullptr}, + {0x3a238b9f, "AndroidCryptoNative_RsaVerificationPrimitive", nullptr}, + {0x3a861d34, "SystemNative_GetNativeIPInterfaceStatistics", nullptr}, + {0x3af56a10, "AndroidCryptoNative_RsaSize", nullptr}, + {0x3b286185, "GlobalizationNative_ChangeCaseTurkish", nullptr}, + {0x3bf3d465, "SystemNative_GetIPv6MulticastOption", nullptr}, + {0x3cb49aae, "SystemNative_GetPwNamR", nullptr}, + {0x3d150bdf, "AndroidCryptoNative_Aes128Ecb", nullptr}, + {0x3d823979, "GlobalizationNative_ToUnicode", nullptr}, + {0x3da52690, "SystemNative_FcntlCanGetSetPipeSz", nullptr}, + {0x3de52faf, "AndroidCryptoNative_CipherUpdateAAD", nullptr}, + {0x3df8d649, "SystemNative_SetDelayedSigChildConsoleConfigurationHandler", nullptr}, + {0x3e175e7c, "AndroidCryptoNative_Aes256Cfb128", nullptr}, + {0x3e273961, "SystemNative_StrErrorR", nullptr}, + {0x3e48f022, "SystemNative_GetMaximumAddressSize", nullptr}, + {0x3e778b38, "BrotliDecoderVersion", nullptr}, + {0x3ea31c40, "SystemNative_GetAddressFamily", nullptr}, + {0x3efdb5a0, "SystemNative_SendMessage", nullptr}, + {0x3f47618f, "CryptoNative_EnsureOpenSslInitialized", nullptr}, + {0x3f793993, "SystemNative_LowLevelMonitor_Signal_Release", nullptr}, + {0x40b0026c, "CompressionNative_DeflateEnd", nullptr}, + {0x40e64bdd, "CryptoNative_ErrClearError", nullptr}, + {0x413b9801, "SystemNative_Read", nullptr}, + {0x41818c1d, "SystemNative_GetPriority", nullptr}, + {0x41cf0c16, "AndroidCryptoNative_CipherCreate", nullptr}, + {0x42955366, "SystemNative_Disconnect", nullptr}, + {0x42afcfbb, "AndroidCryptoNative_CipherCreatePartial", nullptr}, + {0x430352b3, "SystemNative_GetNameInfo", nullptr}, + {0x43f6cea1, "AndroidCryptoNative_DesCfb8", nullptr}, + {0x4543d533, "AndroidCryptoNative_EcDsaVerify", nullptr}, + {0x45a00971, "GlobalizationNative_CloseSortHandle", nullptr}, + {0x45f09dca, "AndroidCryptoNative_CipherSetTagLength", nullptr}, + {0x46268e76, "GlobalizationNative_GetCalendarInfo", nullptr}, + {0x477f60cf, "SystemNative_OpenDir", nullptr}, + {0x47a82b4e, "SystemNative_AlignedRealloc", nullptr}, + {0x48c17c9b, "SystemNative_Sysctl", nullptr}, + {0x493888ee, "CompressionNative_Crc32", nullptr}, + {0x494ef6d4, "SystemNative_GetIPv4MulticastOption", nullptr}, + {0x496f1885, "SystemNative_GetSocketErrorOption", nullptr}, + {0x49c2af32, "SystemNative_GetBootTimeTicks", nullptr}, + {0x49c81782, "SystemNative_MkDir", nullptr}, + {0x49f60a0f, "GlobalizationNative_GetLocales", nullptr}, + {0x4a4ef46f, "SystemNative_FcntlGetFD", nullptr}, + {0x4a98a396, "GlobalizationNative_GetLocaleInfoInt", nullptr}, + {0x4b78d330, "CryptoNative_HmacCurrent", nullptr}, + {0x4c2eae6c, "GlobalizationNative_EnumCalendarInfo", nullptr}, + {0x4c6d50ba, "SystemNative_GetIPv4GlobalStatistics", nullptr}, + {0x4ca38207, "AndroidCryptoNative_X509StoreEnumerateTrustedCertificates", nullptr}, + {0x4cb997ae, "BrotliEncoderCompress", nullptr}, + {0x4d1a35d1, "SystemNative_LowLevelMonitor_Release", nullptr}, + {0x4d75bb15, "SystemNative_WaitIdAnyExitedNoHangNoWait", nullptr}, + {0x4dbf0c74, "SystemNative_CreateSocketEventBuffer", nullptr}, + {0x4e4d4f2a, "SystemNative_SetIPv6Address", nullptr}, + {0x4f6011da, "SystemNative_GetPort", nullptr}, + {0x4f6c3726, "SystemNative_FcntlGetIsNonBlocking", nullptr}, + {0x50e88639, "CryptoNative_HmacUpdate", nullptr}, + {0x514e739b, "AndroidCryptoNative_EcKeyCreateByExplicitParameters", nullptr}, + {0x52590509, "AndroidCryptoNative_Aes128Cbc", nullptr}, + {0x526c9f90, "SystemNative_GetNumRoutes", nullptr}, + {0x52896a81, "SystemNative_ChMod", nullptr}, + {0x538521c9, "GlobalizationNative_IanaIdToWindowsId", nullptr}, + {0x54d6c29d, "GlobalizationNative_GetJapaneseEraStartDate", nullptr}, + {0x5600bd0d, "AndroidCryptoNative_SSLStreamCreate", nullptr}, + {0x561fb6ff, "SystemNative_FStat", nullptr}, + {0x564f6794, "AndroidCryptoNative_Pbkdf2", nullptr}, + {0x56993aa9, "SystemNative_SetKeypadXmit", nullptr}, + {0x57bdcc46, "SystemNative_Open", nullptr}, + {0x581adfc6, "SystemNative_GetSignalForBreak", nullptr}, + {0x5906e1ba, "SystemNative_Close", nullptr}, + {0x591c5746, "AndroidCryptoNative_EcKeyUpRef", nullptr}, + {0x59840533, "AndroidCryptoNative_X509Decode", nullptr}, + {0x5989ad17, "SystemNative_GetIcmpv4GlobalStatistics", nullptr}, + {0x599921d3, "SystemNative_SysConf", nullptr}, + {0x59b67f4d, "AndroidCryptoNative_SSLGetSupportedProtocols", nullptr}, + {0x59e712d5, "SystemNative_MkdTemp", nullptr}, + {0x5a492732, "SystemNative_FcntlSetFD", nullptr}, + {0x5ccc38dd, "AndroidCryptoNative_SSLStreamGetPeerCertificates", nullptr}, + {0x5e9ef1a2, "SystemNative_GetAtOutOfBandMark", nullptr}, + {0x5eb4f827, "SystemNative_LockFileRegion", nullptr}, + {0x5ed67634, "SystemNative_GetPwUidR", nullptr}, + {0x5efc6409, "SystemNative_ReceiveSocketError", nullptr}, + {0x5f706f52, "AndroidCryptoNative_RsaSignPrimitive", nullptr}, + {0x5fc58bed, "SystemNative_GetEstimatedTcpConnectionCount", nullptr}, + {0x60571eb9, "AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration", nullptr}, + {0x6068baa0, "AndroidCryptoNative_GetRsaParameters", nullptr}, + {0x608ee1a5, "SystemNative_Calloc", nullptr}, + {0x60c353e5, "SystemNative_SetPosixSignalHandler", nullptr}, + {0x613c0080, "AndroidCryptoNative_Aes192Ccm", nullptr}, + {0x626db703, "SystemNative_LStat", nullptr}, + {0x6288dd9a, "SystemNative_SetSignalForBreak", nullptr}, + {0x62a36e75, "AndroidCryptoNative_X509ChainGetErrorCount", nullptr}, + {0x639b2b1d, "AndroidCryptoNative_DsaVerify", nullptr}, + {0x6436999d, "AndroidCryptoNative_SSLStreamRead", nullptr}, + {0x6441bc65, "CryptoNative_EvpSha256", nullptr}, + {0x64f12e5b, "BrotliDecoderIsFinished", nullptr}, + {0x661c5218, "SystemNative_GetDomainName", nullptr}, + {0x6661a841, "BrotliDecoderDecompressStream", nullptr}, + {0x66b5bf9d, "GlobalizationNative_IsPredefinedLocale", nullptr}, + {0x674bdf7f, "SystemNative_DisablePosixSignalHandling", nullptr}, + {0x679dd832, "SystemNative_SetPort", nullptr}, + {0x679f9b4e, "SystemNative_FcntlGetPipeSz", nullptr}, + {0x67de0842, "SystemNative_Dup", nullptr}, + {0x687726ff, "AndroidCryptoNative_EcKeyGetCurveName", nullptr}, + {0x68bdc398, "SystemNative_INotifyAddWatch", nullptr}, + {0x68c949a0, "AndroidCryptoNative_X509GetContentType", nullptr}, + {0x68f9f52f, "AndroidCryptoNative_CipherIsSupported", nullptr}, + {0x6907c8eb, "BrotliEncoderSetParameter", nullptr}, + {0x6adb646e, "SystemNative_ReadDirR", nullptr}, + {0x6b5343a0, "SystemNative_SetErrNo", nullptr}, + {0x6bbd3d10, "SystemNative_GetRLimit", nullptr}, + {0x6be1e33d, "SystemNative_EnumerateInterfaceAddresses", nullptr}, + {0x6cda2cf8, "SystemNative_SetSendTimeout", nullptr}, + {0x6d48392a, "SystemNative_Stat", nullptr}, + {0x6ece5fe6, "SystemNative_GetPid", nullptr}, + {0x6ef4e421, "AndroidCryptoNative_CipherDestroy", nullptr}, + {0x6f18d737, "GlobalizationNative_InitICUFunctions", nullptr}, + {0x6f695cb8, "SystemNative_RmDir", nullptr}, + {0x6fa886b1, "SystemNative_GetSockName", nullptr}, + {0x6fc36e5f, "GlobalizationNative_StartsWith", nullptr}, + {0x708e7911, "SystemNative_SetIPv4Address", nullptr}, + {0x70d4f7e6, "SystemNative_GetActiveTcpConnectionInfos", nullptr}, + {0x70e91ddd, "SystemNative_FChMod", nullptr}, + {0x71698a7f, "SystemNative_GetDomainSocketSizes", nullptr}, + {0x7243c4b4, "AndroidCryptoNative_Des3Cfb8", nullptr}, + {0x758dd6aa, "SystemNative_GetTimeZoneData", nullptr}, + {0x759f5b1e, "AndroidCryptoNative_Aes256Cfb8", nullptr}, + {0x75b11f61, "BrotliDecoderGetErrorCode", nullptr}, + {0x76e97b2e, "SystemNative_Rename", nullptr}, + {0x78c1eb52, "AndroidCryptoNative_Des3Ecb", nullptr}, + {0x7a0529c1, "SystemNative_InitializeTerminalAndSignalHandling", nullptr}, + {0x7a4012d2, "GlobalizationNative_GetICUVersion", nullptr}, + {0x7aa30494, "Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate", nullptr}, + {0x7ad3b820, "AndroidCryptoNative_Aes192Cfb128", nullptr}, + {0x7cb19137, "SystemNative_GetIcmpv6GlobalStatistics", nullptr}, + {0x7d0c477d, "CryptoNative_ErrPeekLastError", nullptr}, + {0x7d2bb98a, "SystemNative_MksTemps", nullptr}, + {0x7de70253, "SystemNative_ConvertErrorPalToPlatform", nullptr}, + {0x7e882ae5, "BrotliEncoderIsFinished", nullptr}, + {0x7e9a677b, "GlobalizationNative_GetSortVersion", nullptr}, + {0x7f5d9e25, "SystemNative_MUnmap", nullptr}, + {0x80d5027e, "CryptoNative_EvpMdCtxCopyEx", nullptr}, + {0x80deced4, "SystemNative_CreateAutoreleasePool", nullptr}, + {0x81a5efac, "SystemNative_SetEUid", nullptr}, + {0x82484cbf, "CryptoNative_EvpDigestOneShot", nullptr}, + {0x8289a6f7, "BrotliDefaultFreeFunc", nullptr}, + {0x83dad9bf, "SystemNative_Pipe", nullptr}, + {0x83db1b72, "CryptoNative_EvpDigestCurrent", nullptr}, + {0x84662605, "CompressionNative_Deflate", nullptr}, + {0x8526c9e8, "SystemNative_SetRawSockOpt", nullptr}, + {0x8574b133, "AndroidCryptoNative_Aes192Ecb", nullptr}, + {0x85abed93, "GlobalizationNative_GetCalendars", nullptr}, + {0x8808879d, "AndroidCryptoNative_X509StoreGetPrivateKeyEntry", nullptr}, + {0x88a7558d, "SystemNative_GetDefaultSearchOrderPseudoHandle", nullptr}, + {0x8ba80ef4, "GlobalizationNative_InitOrdinalCasingPage", nullptr}, + {0x8bdaf06c, "SystemNative_GetWindowSize", nullptr}, + {0x8bfcd7ba, "CompressionNative_Inflate", nullptr}, + {0x8d38b733, "SystemNative_LSeek", nullptr}, + {0x8f4e59f1, "SystemNative_ReadStdin", nullptr}, + {0x8f628a8d, "GlobalizationNative_CompareString", nullptr}, + {0x909e12ee, "SystemNative_SearchPath", nullptr}, + {0x910b7740, "SystemNative_GetFormatInfoForMountPoint", nullptr}, + {0x913a3d68, "SystemNative_GetDeviceIdentifiers", nullptr}, + {0x9216d936, "SystemNative_GetGroupName", nullptr}, + {0x94477030, "AndroidCryptoNative_Aes256Ccm", nullptr}, + {0x95e99740, "AndroidCryptoNative_SSLStreamInitialize", nullptr}, + {0x960d4fc0, "SystemNative_GetDefaultTimeZone", nullptr}, + {0x966f54af, "CryptoNative_EvpSha384", nullptr}, + {0x96912459, "AndroidCryptoNative_X509GetCertificateForPrivateKeyEntry", nullptr}, + {0x9787b4b4, "CryptoNative_EvpMdSize", nullptr}, + {0x98105435, "SystemNative_GetIPv6Address", nullptr}, + {0x984edaf1, "AndroidCryptoNative_RsaDestroy", nullptr}, + {0x9852b0fa, "SystemNative_INotifyRemoveWatch", nullptr}, + {0x98954db8, "AndroidCryptoNative_X509StoreOpenDefault", nullptr}, + {0x98ca7f1c, "SystemNative_ChDir", nullptr}, + {0x990163b4, "SystemNative_Receive", nullptr}, + {0x996952b3, "AndroidCryptoNative_CipherFinalEx", nullptr}, + {0x9a005080, "SystemNative_Bind", nullptr}, + {0x9a84ffd3, "AndroidCryptoNative_ChaCha20Poly1305", nullptr}, + {0x9abfce84, "SystemNative_GetEnviron", nullptr}, + {0x9bda7eb1, "SystemNative_ReadProcessStatusInfo", nullptr}, + {0x9cd6cae8, "AndroidCryptoNative_SSLStreamRelease", nullptr}, + {0x9d102d58, "CompressionNative_InflateEnd", nullptr}, + {0x9d2f90cf, "GlobalizationNative_GetLatestJapaneseEra", nullptr}, + {0x9d7f4af6, "SystemNative_ReceiveMessage", nullptr}, + {0x9dc3baed, "SystemNative_LowLevelMonitor_Destroy", nullptr}, + {0x9e366e9c, "SystemNative_InterfaceNameToIndex", nullptr}, + {0x9e717f20, "SystemNative_LChflagsCanSetHiddenFlag", nullptr}, + {0x9f47b32d, "SystemNative_ShmOpen", nullptr}, + {0x9feb81cb, "SystemNative_SNPrintF_1I", nullptr}, + {0xa0db1858, "SystemNative_GetEnv", nullptr}, + {0xa1295a9f, "SystemNative_MkFifo", nullptr}, + {0xa1bec9da, "SystemNative_LogError", nullptr}, + {0xa1d774fc, "BrotliEncoderHasMoreOutput", nullptr}, + {0xa2430b33, "SystemNative_SearchPath_TempDirectory", nullptr}, + {0xa25daa0e, "BrotliSetDictionaryData", nullptr}, + {0xa2d2f390, "SystemNative_TryChangeSocketEventRegistration", nullptr}, + {0xa39be756, "GlobalizationNative_LoadICU", nullptr}, + {0xa4636764, "AndroidCryptoNative_X509ChainCreateContext", nullptr}, + {0xa477c74e, "SystemNative_TryGetIPPacketInformation", nullptr}, + {0xa635da0f, "AndroidCryptoNative_SSLStreamShutdown", nullptr}, + {0xa691d151, "AndroidCryptoNative_Aes192Cbc", nullptr}, + {0xa72ce322, "AndroidCryptoNative_DeleteGlobalReference", nullptr}, + {0xa8074d4c, "GlobalizationNative_GetSortHandle", nullptr}, + {0xa826eabe, "SystemNative_FcntlSetIsNonBlocking", nullptr}, + {0xa829138a, "SystemNative_GetProcessPath", nullptr}, + {0xa8701bcf, "AndroidCryptoNative_SSLStreamRequestClientAuthentication", nullptr}, + {0xa8da7ba1, "BrotliEncoderVersion", nullptr}, + {0xa936bc40, "AndroidCryptoNative_EcDsaSize", nullptr}, + {0xa9c29be5, "SystemNative_SetIPv6MulticastOption", nullptr}, + {0xa9c84a4a, "AndroidCryptoNative_X509ExportPkcs7", nullptr}, + {0xaa13ec2b, "GlobalizationNative_GetLocaleInfoGroupingSizes", nullptr}, + {0xaa2f32ad, "SystemNative_FTruncate", nullptr}, + {0xab37a684, "CryptoNative_HmacCreate", nullptr}, + {0xab3d1641, "AndroidCryptoNative_DesEcb", nullptr}, + {0xabe6739f, "BrotliGetDictionary", nullptr}, + {0xacc26fa4, "AndroidCryptoNative_SSLStreamCreateWithCertificates", nullptr}, + {0xacc28460, "SystemNative_GetProcAddress", nullptr}, + {0xad7fbde5, "SystemNative_FUTimens", nullptr}, + {0xae443204, "SystemNative_GetSockOpt", nullptr}, + {0xae449ad1, "BrotliDecoderIsUsed", nullptr}, + {0xae8752e4, "GlobalizationNative_ToAscii", nullptr}, + {0xafb02e71, "BrotliEncoderMaxCompressedSize", nullptr}, + {0xb01e9c27, "AndroidCryptoNative_SSLStreamSetEnabledProtocols", nullptr}, + {0xb030a893, "SystemNative_LowLevelMonitor_Acquire", nullptr}, + {0xb0e270a0, "BrotliEncoderDestroyInstance", nullptr}, + {0xb22a12be, "BrotliEncoderCreateInstance", nullptr}, + {0xb26f05b6, "SystemNative_PWrite", nullptr}, + {0xb2965ccd, "CryptoNative_GetMaxMdSize", nullptr}, + {0xb2985645, "AndroidCryptoNative_X509StoreEnumerateCertificates", nullptr}, + {0xb4110b14, "AndroidCryptoNative_DsaGenerateKey", nullptr}, + {0xb427959c, "SystemNative_FLock", nullptr}, + {0xb439ebdb, "AndroidCryptoNative_RegisterRemoteCertificateValidationCallback", nullptr}, + {0xb444f04a, "SystemNative_Accept", nullptr}, + {0xb448a24a, "SystemNative_SymLink", nullptr}, + {0xb4e5c37d, "SystemNative_UTimensat", nullptr}, + {0xb584e8fb, "GlobalizationNative_GetTimeZoneDisplayName", nullptr}, + {0xb5a5754a, "SystemNative_UninitializeConsoleAfterRead", nullptr}, + {0xb5db6a51, "SystemNative_PWriteV", nullptr}, + {0xb628f475, "SystemNative_GetBytesAvailable", nullptr}, + {0xb7041ffa, "SystemNative_GetControlCharacters", nullptr}, + {0xb7cc3cd1, "AndroidCryptoNative_DesCbc", nullptr}, + {0xb7ebdf2c, "AndroidCryptoNative_X509IsKeyStorePrivateKeyEntry", nullptr}, + {0xb80f233c, "SystemNative_FSync", nullptr}, + {0xb84914f1, "SystemNative_EnumerateGatewayAddressesForInterface", nullptr}, + {0xb862b34e, "AndroidCryptoNative_CipherSetNonceLength", nullptr}, + {0xb884b933, "SystemNative_StdinReady", nullptr}, + {0xb96c2133, "SystemNative_GetErrNo", nullptr}, + {0xb97add7d, "SystemNative_CreateNetworkChangeListenerSocket", nullptr}, + {0xb9e6cb2c, "SystemNative_RealPath", nullptr}, + {0xba284ef4, "CryptoNative_EvpSha1", nullptr}, + {0xbb06f5e1, "AndroidCryptoNative_Aes192Gcm", nullptr}, + {0xbb25ff40, "AndroidCryptoNative_SSLStreamSetTargetHost", nullptr}, + {0xbb2ca4f3, "SystemNative_Link", nullptr}, + {0xbb92466f, "SystemNative_AlignedAlloc", nullptr}, + {0xbd658356, "CryptoNative_ErrErrorStringN", nullptr}, + {0xbdbf2140, "SystemNative_SchedGetAffinity", nullptr}, + {0xbec8a3f2, "SystemNative_FChflags", nullptr}, + {0xbf4eeb78, "AndroidCryptoNative_GetBigNumBytes", nullptr}, + {0xbf9766c3, "AndroidCryptoNative_SSLStreamHandshake", nullptr}, + {0xbfa0ce53, "SystemNative_GetPlatformSignalNumber", nullptr}, + {0xbfaad12d, "BrotliDecoderSetParameter", nullptr}, + {0xc090b1d3, "CryptoNative_EvpSha512", nullptr}, + {0xc0d66913, "SystemNative_GetUnixVersion", nullptr}, + {0xc11dec94, "SystemNative_FAllocate", nullptr}, + {0xc1243135, "AndroidCryptoNative_Aes128Gcm", nullptr}, + {0xc1e4e6f6, "AndroidCryptoNative_BigNumToBinary", nullptr}, + {0xc25ffc33, "BrotliEncoderCompressStream", nullptr}, + {0xc3812682, "AndroidCryptoNative_X509ChainGetErrors", nullptr}, + {0xc3dcc3a0, "AndroidCryptoNative_SetRsaParameters", nullptr}, + {0xc3e6ff56, "SystemNative_LowLevelMonitor_Create", nullptr}, + {0xc475f41c, "AndroidCryptoNative_X509StoreContainsCertificate", nullptr}, + {0xc4ac1723, "AndroidCryptoNative_Aes256Cbc", nullptr}, + {0xc55548f2, "SystemNative_HandleNonCanceledPosixSignal", nullptr}, + {0xc57b40fa, "SystemNative_LoadLibrary", nullptr}, + {0xc5a83c28, "AndroidCryptoNative_SSLStreamCreateWithKeyStorePrivateKeyEntry", nullptr}, + {0xc6d5929c, "SystemNative_LowLevelMonitor_TimedWait", nullptr}, + {0xc6f2fb9e, "AndroidCryptoNative_X509ChainSetCustomTrustStore", nullptr}, + {0xc717b16e, "CryptoNative_EvpMdCtxDestroy", nullptr}, + {0xc746b70c, "AndroidCryptoNative_DsaSign", nullptr}, + {0xc83527e0, "CryptoNative_HmacReset", nullptr}, + {0xc89ccd22, "SystemNative_SchedGetCpu", nullptr}, + {0xc8cce896, "SystemNative_GetSocketType", nullptr}, + {0xc8e06b20, "AndroidCryptoNative_X509ChainGetCertificates", nullptr}, + {0xc9b017c8, "AndroidCryptoNative_EcKeyCreateByOid", nullptr}, + {0xca4dad90, "GlobalizationNative_ChangeCase", nullptr}, + {0xca5aab33, "SystemNative_Sync", nullptr}, + {0xcb458400, "CryptoNative_ErrGetErrorAlloc", nullptr}, + {0xcb746e5c, "SystemNative_SetIPv4MulticastOption", nullptr}, + {0xcb85cd8e, "AndroidCryptoNative_EcdhDeriveKey", nullptr}, + {0xccc0dd15, "SystemNative_RegisterForSigChld", nullptr}, + {0xcdfb627d, "SystemNative_FreeLibrary", nullptr}, + {0xce91e293, "SystemNative_GetGroupList", nullptr}, + {0xcf0912c8, "GlobalizationNative_GetLocaleTimeFormat", nullptr}, + {0xcf9bcc75, "AndroidCryptoNative_Aes256Gcm", nullptr}, + {0xcfa9e6f1, "AndroidCryptoNative_GetDsaParameters", nullptr}, + {0xcff9b341, "SystemNative_GetSystemTimeAsTicks", nullptr}, + {0xd199e841, "SystemNative_GetEstimatedUdpListenerCount", nullptr}, + {0xd24d4849, "SystemNative_Socket", nullptr}, + {0xd298c3b3, "SystemNative_Write", nullptr}, + {0xd378ba49, "CryptoNative_EvpMd5", nullptr}, + {0xd473c64c, "SystemNative_SetReceiveTimeout", nullptr}, + {0xd4b91180, "SystemNative_ForkAndExecProcess", nullptr}, + {0xd6d7b4fb, "AndroidCryptoNative_X509ChainGetCertificateCount", nullptr}, + {0xd71d8c66, "AndroidCryptoNative_Aes256Ecb", nullptr}, + {0xd7ee326b, "AndroidCryptoNative_EcKeyDestroy", nullptr}, + {0xd818a523, "AndroidCryptoNative_CipherCtxSetPadding", nullptr}, + {0xd9458396, "BrotliDecoderCreateInstance", nullptr}, + {0xda040de4, "GlobalizationNative_EndsWith", nullptr}, + {0xdaaa19b2, "SystemNative_GetAllMountPoints", nullptr}, + {0xdac67152, "AndroidCryptoNative_X509StoreAddCertificate", nullptr}, + {0xdad29aeb, "AndroidCryptoNative_CipherUpdate", nullptr}, + {0xdaf0460a, "SystemNative_SendFile", nullptr}, + {0xdbbf4917, "AndroidCryptoNative_SSLStreamGetCipherSuite", nullptr}, + {0xdbdce4ef, "BrotliDefaultAllocFunc", nullptr}, + {0xdbe13a57, "SystemNative_GetCpuUtilization", nullptr}, + {0xdc3cbeec, "CryptoNative_HmacOneShot", nullptr}, + {0xdcaddb21, "AndroidCryptoNative_GetECKeyParameters", nullptr}, + {0xdd274c15, "AndroidCryptoNative_RsaPublicEncrypt", nullptr}, + {0xdd445632, "AndroidCryptoNative_X509ChainValidate", nullptr}, + {0xddd58443, "SystemNative_PReadV", nullptr}, + {0xdea9b9dc, "SystemNative_EnablePosixSignalHandling", nullptr}, + {0xdf0260d8, "GlobalizationNative_GetLocaleInfoString", nullptr}, + {0xdf4f1977, "AndroidCryptoNative_X509PublicKey", nullptr}, + {0xdf5d3dc8, "GlobalizationNative_GetDefaultLocaleName", nullptr}, + {0xdf80df75, "SystemNative_iOSSupportVersion", nullptr}, + {0xe121bac7, "SystemNative_GetPeerID", nullptr}, + {0xe169faa6, "AndroidCryptoNative_SSLStreamSetApplicationProtocols", nullptr}, + {0xe1b8b44f, "SystemNative_Send", nullptr}, + {0xe2a0d0de, "SystemNative_GetSpaceInfoForMountPoint", nullptr}, + {0xe4a78efb, "SystemNative_SetPriority", nullptr}, + {0xe4dba4f6, "SystemNative_GetCwd", nullptr}, + {0xe4f87d25, "AndroidCryptoNative_SSLStreamVerifyHostname", nullptr}, + {0xe50c82b4, "SystemNative_CreateThread", nullptr}, + {0xe58ed8fe, "SystemNative_PlatformSupportsDualModeIPv4PacketInfo", nullptr}, + {0xe5ef37b3, "AndroidCryptoNative_DsaSignatureFieldSize", nullptr}, + {0xe70a3634, "GlobalizationNative_GetLocaleName", nullptr}, + {0xe770cb3f, "SystemNative_CopyFile", nullptr}, + {0xe7a9a106, "CompressionNative_InflateInit2_", nullptr}, + {0xe7bd8dd1, "AndroidCryptoNative_EcKeyCreateByKeyParameters", nullptr}, + {0xe890cf58, "AndroidCryptoNative_EcDsaSign", nullptr}, + {0xe8b2ec8d, "BrotliDecoderErrorString", nullptr}, + {0xe972fbd9, "SystemNative_GetEGid", nullptr}, + {0xe9bc4e53, "SystemNative_SNPrintF_1S", nullptr}, + {0xea86f52f, "BrotliEncoderTakeOutput", nullptr}, + {0xeb0d0522, "SystemNative_LowLevelMonitor_Wait", nullptr}, + {0xebacbf92, "AndroidCryptoNative_Aes128Cfb8", nullptr}, + {0xec31140d, "BrotliDecoderHasMoreOutput", nullptr}, + {0xec51a1b4, "SystemNative_LChflags", nullptr}, + {0xed6cc182, "CryptoNative_EvpMdCtxCreate", nullptr}, + {0xee74a5ad, "AndroidCryptoNative_DsaSizeP", nullptr}, + {0xef48c2eb, "CryptoNative_EvpDigestReset", nullptr}, + {0xef5890c7, "AndroidCryptoNative_Des3Cbc", nullptr}, + {0xefb38c9f, "SystemNative_Poll", nullptr}, + {0xefd277f7, "CryptoNative_HmacFinal", nullptr}, + {0xf06b440b, "AndroidCryptoNative_DsaSizeSignature", nullptr}, + {0xf0919525, "AndroidCryptoNative_CipherReset", nullptr}, + {0xf0e499c4, "SystemNative_PRead", nullptr}, + {0xf1bb5b47, "SystemNative_ReadLink", nullptr}, + {0xf23e6314, "AndroidCryptoNative_RsaCreate", nullptr}, + {0xf2a49cf0, "SystemNative_CloseSocketEventPort", nullptr}, + {0xf39b1c3a, "SystemNative_GetCryptographicallySecureRandomBytes", nullptr}, + {0xf3b9c879, "AndroidCryptoNative_X509Encode", nullptr}, + {0xf432ab33, "SystemNative_CloseDir", nullptr}, + {0xf4a5a1c8, "SystemNative_SysLog", nullptr}, + {0xf500c9d3, "SystemNative_GetActiveUdpListeners", nullptr}, + {0xf57828fb, "SystemNative_IsATty", nullptr}, + {0xf5918f53, "SystemNative_GetSocketAddressSizes", nullptr}, + {0xf6141499, "AndroidCryptoNative_X509ChainBuild", nullptr}, + {0xf629d20f, "SystemNative_Shutdown", nullptr}, + {0xf6b01c6b, "SystemNative_FreeEnviron", nullptr}, + {0xf6bfedad, "SystemNative_ReadEvents", nullptr}, + {0xf91cf365, "AndroidCryptoNative_Aes128Ccm", nullptr}, + {0xf94a4828, "SystemNative_GetEUid", nullptr}, + {0xf993f426, "SystemNative_Free", nullptr}, + {0xfa97914b, "SystemNative_MMap", nullptr}, + {0xfad61722, "AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey", nullptr}, + {0xfae25aa7, "GlobalizationNative_LastIndexOf", nullptr}, + {0xfb89157f, "SystemNative_GetGroups", nullptr}, + {0xfc83423c, "SystemNative_GetRawSockOpt", nullptr}, + {0xfd9099cc, "SystemNative_GetUInt64OSThreadId", nullptr}, + {0xfe2f2c47, "SystemNative_DrainAutoreleasePool", nullptr}, + {0xfeb6c5c7, "SystemNative_WaitPidExitedNoHang", nullptr}, + {0xff3b4cfa, "SystemNative_GetFileSystemType", nullptr}, + {0xff975200, "SystemNative_Realloc", nullptr}, + }}; + + +constexpr hash_t java_interop_library_hash = 0x6e36e350; +constexpr hash_t xa_internal_api_library_hash = 0x13c9bd62; +constexpr hash_t android_liblog_library_hash = 0xa70c9969; +constexpr hash_t system_native_library_hash = 0x5b9ade60; +constexpr hash_t system_io_compression_native_library_hash = 0xafe3142c; +constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93625cd; +constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a; +#endif + +constexpr size_t internal_pinvokes_count = 10; +constexpr size_t dotnet_pinvokes_count = 477; +} // end of anonymous namespace diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc new file mode 100644 index 00000000000..8f1df3cce0f --- /dev/null +++ b/src/native/clr/host/typemap.cc @@ -0,0 +1,319 @@ +#include + +#include +#include +#include +#include +#include +#include + +using namespace xamarin::android; + +namespace { + class MonoGuidString + { + static inline constexpr size_t MVID_SIZE = 16; + static inline constexpr size_t NUM_HYPHENS = 4; + static inline constexpr size_t BUF_SIZE = (MVID_SIZE * 2) + NUM_HYPHENS + 1; + + public: + explicit MonoGuidString (const uint8_t *mvid) noexcept + { + if (mvid == nullptr) { + _ascii_form[0] = '\0'; + return; + } + + // In the caller we trust, we have no way to validate the size here + auto to_hex = [this, &mvid] (size_t &dest_idx, size_t src_idx) { + Util::to_hex (mvid[src_idx], _ascii_form[dest_idx], _ascii_form[dest_idx + 1]); + dest_idx += 2; + }; + + auto hyphen = [this] (size_t &dest_idx) { + _ascii_form[dest_idx++] = '-'; + }; + + size_t dest_idx = 0; + to_hex (dest_idx, 3); to_hex (dest_idx, 2); to_hex (dest_idx, 1); to_hex (dest_idx, 0); + hyphen (dest_idx); + + to_hex (dest_idx, 5); to_hex (dest_idx, 4); + hyphen (dest_idx); + + to_hex (dest_idx, 7); to_hex (dest_idx, 6); + hyphen (dest_idx); + + to_hex (dest_idx, 8); to_hex (dest_idx, 9); + hyphen (dest_idx); + + to_hex (dest_idx, 10); to_hex (dest_idx, 11); to_hex (dest_idx, 12); + to_hex (dest_idx, 13); to_hex (dest_idx, 14); to_hex (dest_idx, 15); + + _ascii_form[_ascii_form.size () - 1] = '\0'; + } + + auto c_str () const noexcept -> const char* + { + return _ascii_form.data (); + } + + private: + std::array _ascii_form; + }; +} + +#if defined(DEBUG) +[[gnu::always_inline]] +auto TypeMapper::typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char* +{ + Helpers::abort_application ("TypeMap support for Debug builds not implemented yet"sv); +} +#endif // def DEBUG + +#if defined(RELEASE) +[[gnu::always_inline]] +auto TypeMapper::compare_mvid (const uint8_t *mvid, TypeMapModule const& module) noexcept -> int +{ + return memcmp (module.module_uuid, mvid, sizeof(module.module_uuid)); +} + +[[gnu::always_inline]] +auto TypeMapper::find_module_entry (const uint8_t *mvid, const TypeMapModule *entries, size_t entry_count) noexcept -> const TypeMapModule* +{ + if (entries == nullptr || mvid == nullptr) [[unlikely]] { + return nullptr; + } + + auto equal = [](TypeMapModule const& entry, const uint8_t *key) -> bool { return compare_mvid (key, entry) == 0; }; + auto less_than = [](TypeMapModule const& entry, const uint8_t *key) -> bool { return compare_mvid (key, entry) < 0; }; + ssize_t idx = Search::binary_search (mvid, entries, entry_count); + if (idx >= 0) [[likely]] { + return &entries[idx]; + } + + return nullptr; +} + +[[gnu::always_inline]] +auto TypeMapper::find_managed_to_java_map_entry (hash_t name_hash, const TypeMapModuleEntry *map, size_t entry_count) noexcept -> const TypeMapModuleEntry* +{ + if (map == nullptr) { + return nullptr; + }; + + auto equal = [](TypeMapModuleEntry const& entry, hash_t key) -> bool { return entry.managed_type_name_hash == key; }; + auto less_than = [](TypeMapModuleEntry const& entry, hash_t key) -> bool { return entry.managed_type_name_hash < key; }; + ssize_t idx = Search::binary_search (name_hash, map, entry_count); + if (idx >= 0) [[likely]] { + return &map[idx]; + } + + return nullptr; +} + +[[gnu::always_inline]] +auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char* +{ + const TypeMapModule *match = find_module_entry (mvid, managed_to_java_map, managed_to_java_map_module_count); + if (match == nullptr) { + if (mvid == nullptr) { + log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); + } else { + log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found."sv, MonoGuidString (mvid).c_str ()); + } + return nullptr; + } + + log_debug (LOG_ASSEMBLY, "typemap: found module matching MVID [{}]"sv, MonoGuidString (mvid).c_str ()); + hash_t name_hash = xxhash::hash (typeName, strlen (typeName)); + + const TypeMapModuleEntry *entry = find_managed_to_java_map_entry (name_hash, match->map, match->entry_count); + if (entry == nullptr) [[unlikely]] { + if (match->map == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).c_str ()); + return nullptr; + } + + if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { + log_debug ( + LOG_ASSEMBLY, + "typemap: searching module [{}] duplicate map for type '{}' (hash {:x})", + MonoGuidString (mvid).c_str (), + optional_string (typeName), + name_hash + ); + entry = find_managed_to_java_map_entry (name_hash, match->duplicate_map, match->duplicate_count); + } + + if (entry == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) not found in module [{}] ({}).", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]) + ); + return nullptr; + } + } + + if (entry->java_map_index >= java_type_count) [[unlikely]] { + log_warn ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) has invalid Java type index {}", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]), + entry->java_map_index + ); + return nullptr; + } + + TypeMapJava const& java_entry = java_to_managed_map[entry->java_map_index]; + if (java_entry.java_name_index >= java_type_count) [[unlikely]] { + log_warn ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]), + entry->java_map_index, + java_entry.java_name_index + ); + + return nullptr; + } + + const char *ret = java_type_names[java_entry.java_name_index]; + if (ret == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}", entry->java_map_index); + } + + log_debug ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) corresponds to Java type '{}'", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]), + ret + ); + + return ret; +} +#endif // def RELEASE + +[[gnu::flatten]] +auto TypeMapper::typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char* +{ + size_t total_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + //timing = new Timing (); + total_time_index = internal_timing.start_event (TimingEventKind::ManagedToJava); + } + + if (typeName == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_managed_to_java"); + return nullptr; + } + + const char *ret = nullptr; +#if defined(RELEASE) + ret = typemap_managed_to_java_release (typeName, mvid); +#else + ret = typemap_managed_to_java_debug (typeName, mvid); +#endif + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.end_event (total_time_index); + } + + return ret; +} + +#if defined(DEBUG) +[[gnu::flatten]] +auto TypeMapper::typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool +{ + Helpers::abort_application ("typemap_java_to_managed not implemented for debug builds yet"); +} +#else // def DEBUG + +[[gnu::always_inline]] +auto TypeMapper::find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava* +{ + ssize_t idx = Search::binary_search (name_hash, java_to_managed_hashes, java_type_count); + if (idx < 0) [[unlikely]] { + return nullptr; + } + + return &java_to_managed_map[idx]; +} + +[[gnu::flatten]] +auto TypeMapper::typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool +{ + if (java_type_name == nullptr || assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { + if (java_type_name == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}", + "java_type_name"sv, + __PRETTY_FUNCTION__ + ); + } + + if (assembly_name == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}", + "assembly_name"sv, + __PRETTY_FUNCTION__ + ); + } + + if (managed_type_token_id == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}", + "managed_type_token_id"sv, + __PRETTY_FUNCTION__ + ); + } + + return false; + } + + hash_t name_hash = xxhash::hash (java_type_name, strlen (java_type_name)); + TypeMapJava const* java_entry = find_java_to_managed_entry (name_hash); + if (java_entry == nullptr) { + log_info ( + LOG_ASSEMBLY, + "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", + optional_string (java_type_name), + name_hash + ); + + return false; + } + + TypeMapModule const &module = managed_to_java_map[java_entry->module_index]; + *assembly_name = managed_assembly_names[module.assembly_name_index]; + *managed_type_token_id = java_entry->managed_type_token_id; + + log_debug ( + LOG_ASSEMBLY, + "Java type '{}' corresponds to managed type '{}' (token 0x{:x} in assembly '{}')", + optional_string (java_type_name), + optional_string (managed_type_names[java_entry->managed_type_name_index]), + *managed_type_token_id, + optional_string (*assembly_name) + ); + + return true; +} +#endif // ndef DEBUG diff --git a/src/native/clr/include/host/assembly-store.hh b/src/native/clr/include/host/assembly-store.hh new file mode 100644 index 00000000000..4648231e958 --- /dev/null +++ b/src/native/clr/include/host/assembly-store.hh @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace xamarin::android { + class AssemblyStore + { + public: + static auto open_assembly (std::string_view const& name, int64_t &size) noexcept -> void*; + + static void map (int fd, std::string_view const& apk_path, std::string_view const& store_path, uint32_t offset, uint32_t size) noexcept; + + static void map (int fd, std::string_view const& file_path, uint32_t offset, uint32_t size) noexcept + { + map (fd, {}, file_path, offset, size); + } + + private: + static void set_assembly_data_and_size (uint8_t* source_assembly_data, uint32_t source_assembly_data_size, uint8_t*& dest_assembly_data, uint32_t& dest_assembly_data_size) noexcept; + + // Returns a tuple of + static auto get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name, bool force_rw = false) noexcept -> std::tuple; + static auto find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept -> const AssemblyStoreIndexEntry*; + + private: + static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; + static inline std::mutex assembly_decompress_mutex {}; + }; +} diff --git a/src/native/clr/include/host/host-jni.hh b/src/native/clr/include/host/host-jni.hh new file mode 100644 index 00000000000..4904644ebd8 --- /dev/null +++ b/src/native/clr/include/host/host-jni.hh @@ -0,0 +1,48 @@ +#pragma once + +#include + +extern "C" { + /* + * Class: mono_android_Runtime + * Method: initInternal + * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;ILjava/lang/ClassLoader;[Ljava/lang/String;IZZ)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_initInternal(JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jint, jobject, jobjectArray, jboolean, jboolean); + + /* + * Class: mono_android_Runtime + * Method: dumpTimingData + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_dumpTimingData (JNIEnv *, jclass); + + /* + * Class: mono_android_Runtime + * Method: initInternal + * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;ILjava/lang/ClassLoader;[Ljava/lang/String;IZZ)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_initInternal (JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jint, jobject, jobjectArray, jboolean, jboolean); + + /* + * Class: mono_android_Runtime + * Method: notifyTimeZoneChanged + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_notifyTimeZoneChanged (JNIEnv *, jclass); + + /* + * Class: mono_android_Runtime + * Method: propagateUncaughtException + * Signature: (Ljava/lang/Thread;Ljava/lang/Throwable;)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_propagateUncaughtException (JNIEnv *, jclass, jobject, jthrowable); + + /* + * Class: mono_android_Runtime + * Method: register + * Signature: (Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_register (JNIEnv *, jclass, jstring, jclass, jstring); + +} diff --git a/src/native/clr/include/host/host-util.hh b/src/native/clr/include/host/host-util.hh new file mode 100644 index 00000000000..8fb9edc0873 --- /dev/null +++ b/src/native/clr/include/host/host-util.hh @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace xamarin::android { + class HostUtil + { + public: + static auto get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) noexcept -> jclass; + }; +} diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh new file mode 100644 index 00000000000..a1e70ca8135 --- /dev/null +++ b/src/native/clr/include/host/host.hh @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +#include +#include + +#include +#include "../runtime-base/timing.hh" +#include "../shared/log_types.hh" +#include "managed-interface.hh" + +namespace xamarin::android { + class Host + { + public: + static auto Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint; + static void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, + jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, + jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) noexcept; + static void Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods) noexcept; + + static auto get_java_class_name_for_TypeManager (jclass klass) noexcept -> char*; + + static auto get_timing () -> Timing* + { + return _timing.get (); + } + + private: + static void create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept; + static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept; + static auto zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size) -> bool; + static void gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks); + + static size_t clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept; + static bool clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept; + static const void* clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept; + static void clr_error_writer (const char *message) noexcept; + + static auto create_delegate ( + std::string_view const& assembly_name, std::string_view const& type_name, + std::string_view const& method_name) noexcept -> void*; + + private: + static inline void *clr_host = nullptr; + static inline unsigned int domain_id = 0; + static inline std::unique_ptr _timing{}; + static inline bool found_assembly_store = false; + static inline jnienv_register_jni_natives_fn jnienv_register_jni_natives = nullptr; + + static inline JavaVM *jvm = nullptr; + static inline jmethodID Class_getName = nullptr; + + static inline host_runtime_contract runtime_contract{ + .size = sizeof(host_runtime_contract), + .context = nullptr, + .get_runtime_property = clr_get_runtime_property, + .bundle_probe = nullptr, + .pinvoke_override = clr_pinvoke_override, + .external_assembly_probe = clr_external_assembly_probe, + }; + + // Enough to fit 0xffffffffffffffff + terminating NUL + static inline std::array host_contract_ptr_buffer{}; + }; +} diff --git a/src/native/clr/include/host/os-bridge.hh b/src/native/clr/include/host/os-bridge.hh new file mode 100644 index 00000000000..0bce2a180fb --- /dev/null +++ b/src/native/clr/include/host/os-bridge.hh @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include + +#include "../runtime-base/logger.hh" + +namespace xamarin::android { + class OSBridge + { + public: + static void initialize_on_onload (JavaVM *vm, JNIEnv *env) noexcept; + static void initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept; + static auto lref_to_gref (JNIEnv *env, jobject lref) noexcept -> jobject; + + static auto get_gc_gref_count () noexcept -> int + { + return gc_gref_count; + } + + static auto get_gc_weak_gref_count () noexcept -> int + { + return gc_weak_gref_count; + } + + static void _monodroid_gref_log (const char *message) noexcept; + static auto _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept -> int; + static void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; + + static auto ensure_jnienv () noexcept -> JNIEnv* + { + JNIEnv *env = nullptr; + jvm->GetEnv ((void**)&env, JNI_VERSION_1_6); + if (env == nullptr) { + // TODO: attach to the runtime thread here + jvm->GetEnv ((void**)&env, JNI_VERSION_1_6); + abort_unless (env != nullptr, "Unable to get a valid pointer to JNIEnv"); + } + + return env; + } + + private: + static auto _monodroid_gref_inc () noexcept -> int; + static auto _monodroid_gref_dec () noexcept -> int; + static auto _get_stack_trace_line_end (char *m) noexcept -> char*; + static void _write_stack_trace (FILE *to, char *from, LogCategories = LOG_NONE) noexcept; + + private: + static inline JavaVM *jvm = nullptr; + static inline jclass GCUserPeer_class = nullptr; + static inline jmethodID GCUserPeer_ctor = nullptr; + + static inline int gc_gref_count = 0; + static inline int gc_weak_gref_count = 0; + }; +} diff --git a/src/native/clr/include/host/pinvoke-override.hh b/src/native/clr/include/host/pinvoke-override.hh new file mode 100644 index 00000000000..e1b7afebd95 --- /dev/null +++ b/src/native/clr/include/host/pinvoke-override.hh @@ -0,0 +1,223 @@ +#pragma once + +#include +#include + +// NDEBUG causes robin_map.h not to include which, in turn, prevents indirect inclusion of . +// conflicts with our std::mutex definition in cppcompat.hh +#if !defined (NDEBUG) +#define NDEBUG +#define NDEBUG_UNDEFINE +#endif + +// hush some compiler warnings +#if defined (__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + +#include + +#if defined (__clang__) +#pragma clang diagnostic pop +#endif // __clang__ + +#if defined (NDEBUG_UNDEFINE) +#undef NDEBUG +#undef NDEBUG_UNDEFINE +#endif + +#include "../runtime-base/monodroid-dl.hh" +#include + +namespace xamarin::android { + struct PinvokeEntry + { + hash_t hash; + const char *name; + void *func; + }; + + struct string_hash + { + [[gnu::always_inline]] + xamarin::android::hash_t operator() (std::string const& s) const noexcept + { + return xamarin::android::xxhash::hash (s.c_str (), s.length ()); + } + }; + + class PinvokeOverride + { + using pinvoke_api_map = tsl::robin_map< + std::string, + void*, + string_hash, + std::equal_to, + std::allocator>, + true + >; + + using pinvoke_api_map_ptr = pinvoke_api_map*; + using pinvoke_library_map = tsl::robin_map< + std::string, + pinvoke_api_map_ptr, + string_hash, + std::equal_to, + std::allocator>, + true + >; + + static inline constexpr pinvoke_library_map::size_type LIBRARY_MAP_INITIAL_BUCKET_COUNT = 1uz; + + public: + [[gnu::always_inline]] + static auto load_library_symbol (const char *library_name, const char *symbol_name, void **dso_handle = nullptr) noexcept -> void* + { + void *lib_handle = dso_handle == nullptr ? nullptr : *dso_handle; + + if (lib_handle == nullptr) { + // We're being called as part of the p/invoke mechanism, we don't need to look in the AOT cache + constexpr bool PREFER_AOT_CACHE = false; + lib_handle = MonodroidDl::monodroid_dlopen (library_name, microsoft::java_interop::JAVA_INTEROP_LIB_LOAD_LOCALLY, PREFER_AOT_CACHE); + if (lib_handle == nullptr) { + log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", optional_string (library_name), optional_string (symbol_name)); + return nullptr; + } + + if (dso_handle != nullptr) { + void *expected_null = nullptr; + if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { + log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", optional_string (library_name)); + } + } + } + + void *entry_handle = MonodroidDl::monodroid_dlsym (lib_handle, symbol_name); + if (entry_handle == nullptr) { + log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", optional_string (library_name), optional_string (symbol_name)); + return nullptr; + } + + return entry_handle; + } + + static auto load_library_entry (std::string const& library_name, std::string const& entrypoint_name, pinvoke_api_map_ptr api_map) noexcept -> void* + { + // Make sure some other thread hasn't just added the entry + auto iter = api_map->find (entrypoint_name); + if (iter != api_map->end () && iter->second != nullptr) { + return iter->second; + } + + void *entry_handle = load_library_symbol (library_name.c_str (), entrypoint_name.c_str ()); + if (entry_handle == nullptr) { + // error already logged + return nullptr; + } + + log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); + (*api_map)[entrypoint_name] = entry_handle; + return entry_handle; + } + + static void load_library_entry (const char *library_name, const char *entrypoint_name, PinvokeEntry &entry, void **dso_handle) noexcept + { + void *entry_handle = load_library_symbol (library_name, entrypoint_name, dso_handle); + void *expected_null = nullptr; + + bool already_loaded = !__atomic_compare_exchange ( + /* ptr */ &entry.func, + /* expected */ &expected_null, + /* desired */ &entry_handle, + /* weak */ false, + /* success_memorder */ __ATOMIC_ACQUIRE, + /* failure_memorder */ __ATOMIC_RELAXED + ); + + if (already_loaded) { + log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); + } + } + + static auto fetch_or_create_pinvoke_map_entry (std::string const& library_name, std::string const& entrypoint_name, hash_t entrypoint_name_hash, pinvoke_api_map_ptr api_map, bool need_lock) noexcept -> void* + { + auto iter = api_map->find (entrypoint_name, entrypoint_name_hash); + if (iter != api_map->end () && iter->second != nullptr) { + return iter->second; + } + + if (!need_lock) { + return load_library_entry (library_name, entrypoint_name, api_map); + } + + StartupAwareLock lock (pinvoke_map_write_lock); + return load_library_entry (library_name, entrypoint_name, api_map); + } + + [[gnu::always_inline]] + static auto find_pinvoke_address (hash_t hash, const PinvokeEntry *entries, size_t entry_count) noexcept -> PinvokeEntry* + { + while (entry_count > 0uz) { + const size_t mid = entry_count / 2uz; + const PinvokeEntry *const ret = entries + mid; + const std::strong_ordering result = hash <=> ret->hash; + + if (result < 0) { + entry_count = mid; + } else if (result > 0) { + entries = ret + 1; + entry_count -= mid + 1uz; + } else { + return const_cast(ret); + } + } + + return nullptr; + } + + [[gnu::always_inline, gnu::flatten]] + static auto handle_other_pinvoke_request (const char *library_name, hash_t library_name_hash, const char *entrypoint_name, hash_t entrypoint_name_hash) noexcept -> void* + { + std::string lib_name {library_name}; + std::string entry_name {entrypoint_name}; + + auto iter = other_pinvoke_map.find (lib_name, library_name_hash); + void *handle = nullptr; + if (iter == other_pinvoke_map.end ()) { + StartupAwareLock lock (pinvoke_map_write_lock); + + pinvoke_api_map_ptr lib_map; + // Make sure some other thread hasn't just added the map + iter = other_pinvoke_map.find (lib_name, library_name_hash); + if (iter == other_pinvoke_map.end () || iter->second == nullptr) { + lib_map = new pinvoke_api_map (1); + other_pinvoke_map[lib_name] = lib_map; + } else { + lib_map = iter->second; + } + + handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); + } else { + if (iter->second == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", optional_string (library_name)); + return nullptr; // fall back to `monodroid_dlopen` + } + + handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, iter->second, /* need_lock */ true); + } + + return handle; + } + + static auto monodroid_pinvoke_override (const char *library_name, const char *entrypoint_name) noexcept -> void*; + + private: + static inline std::mutex pinvoke_map_write_lock{}; + static inline pinvoke_library_map other_pinvoke_map{}; + static inline void *system_native_library_handle = nullptr; + static inline void *system_security_cryptography_native_android_library_handle = nullptr; + static inline void *system_io_compression_native_library_handle = nullptr; + static inline void *system_globalization_native_library_handle = nullptr; + }; +} diff --git a/src/native/clr/include/host/typemap.hh b/src/native/clr/include/host/typemap.hh new file mode 100644 index 00000000000..f695f0ce5d4 --- /dev/null +++ b/src/native/clr/include/host/typemap.hh @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "../runtime-base/logger.hh" +#include +#include "../xamarin-app.hh" + +namespace xamarin::android { + class TypeMapper + { + public: + static auto typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char*; + static auto typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_doken_id) noexcept -> bool; + + private: +#if defined(RELEASE) + static auto compare_mvid (const uint8_t *mvid, TypeMapModule const& module) noexcept -> int; + static auto find_module_entry (const uint8_t *mvid, const TypeMapModule *entries, size_t entry_count) noexcept -> const TypeMapModule*; + static auto find_managed_to_java_map_entry (hash_t name_hash, const TypeMapModuleEntry *map, size_t entry_count) noexcept -> const TypeMapModuleEntry*; + static auto typemap_managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char*; + + static auto find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava*; +#else + static auto typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char*; +#endif + }; +} diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh new file mode 100644 index 00000000000..44ba6fb99cb --- /dev/null +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "logger.hh" + +int _monodroid_gref_get () noexcept; +void _monodroid_gref_log (const char *message) noexcept; +int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept; +void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; +const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept; +bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept; +void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; +char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; +void monodroid_free (void *ptr) noexcept; diff --git a/src/native/clr/include/runtime-base/timing-internal.hh b/src/native/clr/include/runtime-base/timing-internal.hh index 6897c34df1d..185f786bff7 100644 --- a/src/native/clr/include/runtime-base/timing-internal.hh +++ b/src/native/clr/include/runtime-base/timing-internal.hh @@ -88,12 +88,15 @@ namespace xamarin::android { static constexpr uint32_t ns_in_second = ms_in_second * ns_in_millisecond; protected: - FastTiming () noexcept + void configure_for_use () noexcept { events.reserve (INITIAL_EVENT_VECTOR_SIZE); } public: + constexpr FastTiming () noexcept + {} + [[gnu::always_inline]] static auto enabled () noexcept -> bool { @@ -462,5 +465,5 @@ namespace xamarin::android { static inline bool immediate_logging = false; }; - extern FastTiming *internal_timing; + extern FastTiming internal_timing; } diff --git a/src/native/clr/include/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 78100e05a71..efa658fa782 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -41,12 +41,25 @@ namespace xamarin::android { class Util { + static constexpr inline std::array hex_map { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + }; + public: static int create_directory (const char *pathname, mode_t mode); static void create_public_directory (std::string_view const& dir); static auto monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE*; static void set_world_accessable (std::string_view const& path); + // Puts higher half of the `value` byte as a hexadecimal character in `high_half` and + // the lower half in `low_half` + static void to_hex (uint8_t value, char &high_half, char &low_half) noexcept + { + high_half = hex_map[(value & 0xf0) >> 4]; + low_half = hex_map[value & 0x0f]; + } + static auto should_log (LogCategories category) noexcept -> bool { return (log_categories & category) != 0; diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index c65896eb93b..d2a7899dfe5 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -1,14 +1,14 @@ // Dear Emacs, this is a -*- C++ -*- header #pragma once +#include #include #include -#include #include -static constexpr uint64_t FORMAT_TAG = 0x00035E6972616D58; // 'Xmari^XY' where XY is the format version +static constexpr uint64_t FORMAT_TAG = 0x00045E6972616D58; // 'Xmari^XY' where XY is the format version static constexpr uint32_t COMPRESSED_DATA_MAGIC = 0x5A4C4158; // 'XALZ', little-endian static constexpr uint32_t ASSEMBLY_STORE_MAGIC = 0x41424158; // 'XABA', little-endian @@ -74,8 +74,8 @@ struct TypeMap #else struct TypeMapModuleEntry { - uint32_t type_token_id; - uint32_t java_map_index; + xamarin::android::hash_t managed_type_name_hash; + uint32_t java_map_index; }; struct TypeMapModule @@ -83,19 +83,17 @@ struct TypeMapModule uint8_t module_uuid[16]; uint32_t entry_count; uint32_t duplicate_count; + uint32_t assembly_name_index; TypeMapModuleEntry const *map; TypeMapModuleEntry const *duplicate_map; - char const *assembly_name; - uint8_t *image; - uint32_t java_name_width; - uint8_t *java_map; }; struct TypeMapJava { - uint32_t module_index; - uint32_t type_token_id; - uint32_t java_name_index; + uint32_t module_index; + uint32_t managed_type_name_index; + uint32_t managed_type_token_id; + uint32_t java_name_index; }; #endif @@ -315,12 +313,14 @@ extern "C" { #if defined (DEBUG) [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs #else - [[gnu::visibility("default")]] extern const uint32_t map_module_count; + [[gnu::visibility("default")]] extern const uint32_t managed_to_java_map_module_count; [[gnu::visibility("default")]] extern const uint32_t java_type_count; [[gnu::visibility("default")]] extern const char* const java_type_names[]; - [[gnu::visibility("default")]] extern TypeMapModule map_modules[]; - [[gnu::visibility("default")]] extern const TypeMapJava map_java[]; - [[gnu::visibility("default")]] extern const xamarin::android::hash_t map_java_hashes[]; + [[gnu::visibility("default")]] extern const char* const managed_type_names[]; + [[gnu::visibility("default")]] extern const char* const managed_assembly_names[]; + [[gnu::visibility("default")]] extern TypeMapModule managed_to_java_map[]; + [[gnu::visibility("default")]] extern const TypeMapJava java_to_managed_map[]; + [[gnu::visibility("default")]] extern const xamarin::android::hash_t java_to_managed_hashes[]; #endif [[gnu::visibility("default")]] extern CompressedAssemblies compressed_assemblies; @@ -341,7 +341,8 @@ extern "C" { [[gnu::visibility("default")]] extern const RuntimeProperty runtime_properties[]; [[gnu::visibility("default")]] extern const RuntimePropertyIndexEntry runtime_property_index[]; - [[gnu::visibility("default")]] extern const host_configuration_properties host_config_properties; + [[gnu::visibility("default")]] extern const char *init_runtime_property_names[]; + [[gnu::visibility("default")]] extern char *init_runtime_property_values[]; } // diff --git a/src/native/clr/runtime-base/timing-internal.cc b/src/native/clr/runtime-base/timing-internal.cc index fab5e4ed160..8df98638427 100644 --- a/src/native/clr/runtime-base/timing-internal.cc +++ b/src/native/clr/runtime-base/timing-internal.cc @@ -4,13 +4,13 @@ using namespace xamarin::android; namespace xamarin::android { - FastTiming *internal_timing = nullptr; + FastTiming internal_timing; } void FastTiming::really_initialize (bool log_immediately) noexcept { - internal_timing = new FastTiming (); + internal_timing.configure_for_use (); is_enabled = true; immediate_logging = log_immediately; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 0e355298d40..34ee15f4c66 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -22,13 +22,14 @@ const TypeMap type_map = { managed_to_java }; #else -const uint32_t map_module_count = 0; +const uint32_t managed_to_java_map_module_count = 0; const uint32_t java_type_count = 0; const char* const java_type_names[] = {}; - -TypeMapModule map_modules[] = {}; -const TypeMapJava map_java[] = {}; -const xamarin::android::hash_t map_java_hashes[] = {}; +const char* const managed_type_names[] = {}; +const char* const managed_assembly_names[] = {}; +TypeMapModule managed_to_java_map[] = {}; +const TypeMapJava java_to_managed_map[] = {}; +const xamarin::android::hash_t java_to_managed_hashes[] = {}; #endif CompressedAssemblies compressed_assemblies = { @@ -339,26 +340,10 @@ const RuntimePropertyIndexEntry runtime_property_index[] = { }, }; -namespace { - const host_configuration_property _host_configuration_properties_data[] = { - { - .name = u"test_string", - .value = u"string value", - }, - - { - .name = u"test_integer", - .value = u"23", - }, - - { - .name = u"test_boolean", - .value = u"true", - }, - }; -} +const char *init_runtime_property_names[] = { + "HOST_RUNTIME_CONTRACT", +}; -const host_configuration_properties host_config_properties = { - .nitems = 3, - .data = _host_configuration_properties_data, +char *init_runtime_property_values[] { + nullptr, }; diff --git a/src/native/cmake/ArchiveDSOStub.cmake b/src/native/cmake/ArchiveDSOStub.cmake index f11b83372aa..8e4cdd2abac 100644 --- a/src/native/cmake/ArchiveDSOStub.cmake +++ b/src/native/cmake/ArchiveDSOStub.cmake @@ -1,3 +1,3 @@ set(ARCHIVE_DSO_STUB_LIB_NAME "archive-dso-stub") set(ARCHIVE_DSO_STUB_LIB_FILE_NAME "lib${ARCHIVE_DSO_STUB_LIB_NAME}.so") -set(XA_ARCHIVE_STUB_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/dsostubs/${ANDROID_RID}") +set(XA_ARCHIVE_STUB_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}") diff --git a/src/native/common/libstub/CMakeLists.txt b/src/native/common/libstub/CMakeLists.txt index 70563594fc4..28ec03682c0 100644 --- a/src/native/common/libstub/CMakeLists.txt +++ b/src/native/common/libstub/CMakeLists.txt @@ -1,4 +1,4 @@ -set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/libstubs/${ANDROID_RID}") +set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}") set(XAMARIN_STUB_LIB_SOURCES stub.cc diff --git a/src/native/native-clr.csproj b/src/native/native-clr.csproj new file mode 100644 index 00000000000..2bcc54f139a --- /dev/null +++ b/src/native/native-clr.csproj @@ -0,0 +1,27 @@ + + + + netstandard2.0 + Debug + AnyCPU + Exe + false + + + arm64 + arm64-v8a + + + + + + $(NativeRuntimeOutputRootDir)clr + CoreCLR + + + + + + + + diff --git a/src/native/native.targets b/src/native/native.targets index 6b997259f4a..a7825885943 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -112,8 +112,8 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - - <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_LocalDotNetRuntimePath Condition=" '$(CLRLocalRuntimePath)' != '' And '$(CMakeRuntimeFlavor)' == 'CoreCLR' ">-DLOCAL_CORECLR_PATH="$(CLRLocalRuntimePath)" + <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) $(_LocalDotNetRuntimePath) "$(MSBuildThisFileDirectory)"