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)"