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