diff --git a/.gdn/policheck/source.gdnsuppress b/.gdn/policheck/source.gdnsuppress index f73824769dc..564ebc5b8db 100644 --- a/.gdn/policheck/source.gdnsuppress +++ b/.gdn/policheck/source.gdnsuppress @@ -9,7 +9,7 @@ "default": { "name": "default", "createdDate": "2023-02-22 23:55:29Z", - "lastUpdatedDate": "2024-02-22 21:40:38Z" + "lastUpdatedDate": "2024-04-22 13:40:30Z" } }, "results": { @@ -101,10 +101,10 @@ "justification": "Reference to an Android logging function.", "createdDate": "2023-02-22 23:55:29Z" }, - "a2b4d032c59a9d1211d218c3cd550cf8febb369941d70284d07d03ebee855bc0": { - "signature": "a2b4d032c59a9d1211d218c3cd550cf8febb369941d70284d07d03ebee855bc0", + "bca629d8e7888af4116b013c6585b78d0908d248a80138339e0eb1620832eb10": { + "signature": "bca629d8e7888af4116b013c6585b78d0908d248a80138339e0eb1620832eb10", "alternativeSignatures": [ - "9feaec8a73b72e0d212c0e18d863e4fe16ff010c5d33cf8d47d8b0f465cc4c5e" + "f35d63032e4f346c1afcc299d50eb17a0a05ecea81ba3025f14c7fbf78b10100" ], "memberOf": [ "default" @@ -112,10 +112,10 @@ "justification": "Reference to find first set bit function.", "createdDate": "2023-02-22 23:55:29Z" }, - "1c87b45a6044d205dc3f3562f349c238f7cabe22b4609da762df9dc44151e9fb": { - "signature": "1c87b45a6044d205dc3f3562f349c238f7cabe22b4609da762df9dc44151e9fb", + "dc43990fd9fa6a44f2fb2fffcb0497571af4379f23090482035d79a98970e7ae": { + "signature": "dc43990fd9fa6a44f2fb2fffcb0497571af4379f23090482035d79a98970e7ae", "alternativeSignatures": [ - "9feaec8a73b72e0d212c0e18d863e4fe16ff010c5d33cf8d47d8b0f465cc4c5e" + "f35d63032e4f346c1afcc299d50eb17a0a05ecea81ba3025f14c7fbf78b10100" ], "memberOf": [ "default" @@ -123,10 +123,10 @@ "justification": "Reference to find first set bit function.", "createdDate": "2023-02-22 23:55:29Z" }, - "a6639098c4785509a4215c9e2fc10f82c06fce461915dc11a00227ddec558845": { - "signature": "a6639098c4785509a4215c9e2fc10f82c06fce461915dc11a00227ddec558845", + "eb60d4f1e48ca85ad5fa4a413d8ff76c4975bccb12931f51179d67c24a82f354": { + "signature": "eb60d4f1e48ca85ad5fa4a413d8ff76c4975bccb12931f51179d67c24a82f354", "alternativeSignatures": [ - "9feaec8a73b72e0d212c0e18d863e4fe16ff010c5d33cf8d47d8b0f465cc4c5e" + "f35d63032e4f346c1afcc299d50eb17a0a05ecea81ba3025f14c7fbf78b10100" ], "memberOf": [ "default" @@ -134,10 +134,10 @@ "justification": "Reference to find first set bit function.", "createdDate": "2023-02-22 23:55:29Z" }, - "f94ede7b396cb54934db2084f0879cd31a17ce2584eb01e0bfcd35324a724c31": { - "signature": "f94ede7b396cb54934db2084f0879cd31a17ce2584eb01e0bfcd35324a724c31", + "bb80a900ad96e4833eb7f54f55723a3425e846a290dd62b709d4714952cd9d45": { + "signature": "bb80a900ad96e4833eb7f54f55723a3425e846a290dd62b709d4714952cd9d45", "alternativeSignatures": [ - "9feaec8a73b72e0d212c0e18d863e4fe16ff010c5d33cf8d47d8b0f465cc4c5e" + "f35d63032e4f346c1afcc299d50eb17a0a05ecea81ba3025f14c7fbf78b10100" ], "memberOf": [ "default" diff --git a/.gitmodules b/.gitmodules index 20bbd195b37..ac10c71f961 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,7 @@ [submodule "external/constexpr-xxh3"] path = external/constexpr-xxh3 url = https://github.com/chys87/constexpr-xxh3.git +[submodule "external/libunwind"] + path = external/libunwind + url = https://github.com/libunwind/libunwind.git + branch = master diff --git a/Configuration.props b/Configuration.props index f82003642cf..f65e6bf97a1 100644 --- a/Configuration.props +++ b/Configuration.props @@ -104,6 +104,9 @@ True $(MSBuildThisFileDirectory)external\opentk $(MSBuildThisFileDirectory)external\sqlite + $(MSBuildThisFileDirectory)external\libunwind + $(BootstrapOutputDirectory)\libunwind + $(MSBuildThisFileDirectory)external\lz4 $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)src-ThirdParty\ armeabi-v7a;x86 @@ -144,6 +147,9 @@ $([System.IO.Path]::GetFullPath ('$(JavaInteropSourceDirectory)')) $([System.IO.Path]::GetFullPath ('$(MonoSourceDirectory)')) $([System.IO.Path]::GetFullPath ('$(SqliteSourceDirectory)')) + $([System.IO.Path]::GetFullPath ('$(LibUnwindSourceDirectory)')) + $([System.IO.Path]::GetFullPath ('$(LibUnwindGeneratedHeadersDirectory)')) + $([System.IO.Path]::GetFullPath ('$(LZ4SourceDirectory)')) $([System.IO.Path]::GetFullPath ('$(OpenTKSourceDirectory)')) net8.0 diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index c85d197a5aa..eaf3ea4fb2e 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -47,7 +47,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}") = "monodroid", "src\monodroid\monodroid.csproj", "{53EE4C57-1C03-405A-8243-8DA539546C88}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "native", "src\native\native.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/cmake/xa_common.cmake b/build-tools/cmake/xa_common.cmake deleted file mode 100644 index d732318eb05..00000000000 --- a/build-tools/cmake/xa_common.cmake +++ /dev/null @@ -1 +0,0 @@ -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) diff --git a/build-tools/cmake/xa_macros.cmake b/build-tools/cmake/xa_macros.cmake deleted file mode 100644 index df23bdedcd0..00000000000 --- a/build-tools/cmake/xa_macros.cmake +++ /dev/null @@ -1,305 +0,0 @@ -include(CheckCXXCompilerFlag) -include(CheckCCompilerFlag) -include(CheckLinkerFlag) - -macro(_compiler_has_flag _lang _flag) - string(REGEX REPLACE "-|,|=" "_" _flag_name ${_flag}) - string(TOUPPER "${_lang}" _lang_upper) - - cmake_language(CALL check_${_lang}_compiler_flag "${_flag}" HAS_${_flag_name}_${_lang_upper}) - if(HAS_${_flag_name}_${_lang_upper}) - set(COMPILER_FLAG_FOUND True) - else() - set(COMPILER_FLAG_FOUND False) - endif() -endmacro() - -macro(cxx_compiler_has_flag _flag) - _compiler_has_flag(cxx ${_flag}) -endmacro() - -macro(c_compiler_has_flag _flag) - _compiler_has_flag(c ${_flag}) -endmacro() - -macro(_linker_has_flag _lang _flag) - string(REGEX REPLACE "-|,|=" "_" _flag_name ${_flag}) - string(TOUPPER "${_lang}" _lang_upper) - - check_linker_flag(${_lang} "${_flag}" HAS_${_flag_name}_LINKER_${_lang_upper}) - if(HAS_${_flag_name}_LINKER_${_lang_upper}) - set(LINKER_FLAG_FOUND True) - else() - set(LINKER_FLAG_FOUND False) - endif() -endmacro() - -macro(cxx_linker_has_flag _flag) - _linker_has_flag(CXX ${_flag}) -endmacro() - -macro(c_linker_has_flag _flag) - _linker_has_flag(C ${_flag}) -endmacro() - -# -# Uses ${XA_COMMON_COMPILER_FLAGS}, if defined -# -# ${EXTRA_C_FLAGS} contains a set of additional C compiler flags to check -# -# Sets VARNAME on exit -# -macro(xa_check_c_flags VARNAME EXTRA_C_FLAGS) - set(_CHECKED_FLAGS "") - set(_CHECK_FLAGS ${XA_COMMON_COMPILER_FLAGS} ${EXTRA_C_FLAGS}) - - list(LENGTH _CHECK_FLAGS ARGS_LEN) - if(ARGS_LEN LESS_EQUAL 0) - return() - endif() - - foreach(flag ${_CHECK_FLAGS}) - c_compiler_has_flag(${flag}) - if(COMPILER_FLAG_FOUND) - list(APPEND _CHECKED_FLAGS "${flag}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_FLAGS}") -endmacro() - -# -# Uses ${XA_COMMON_COMPILER_FLAGS}, if defined -# -# ${EXTRA_CXX_FLAGS} contains a set of additional C compiler flags to check -# -# Sets VARNAME on exit -# -macro(xa_check_cxx_flags VARNAME EXTRA_CXX_FLAGS) - set(_CHECKED_FLAGS "") - set(_CHECK_FLAGS ${XA_COMMON_COMPILER_FLAGS} ${EXTRA_CXX_FLAGS}) - - list(LENGTH _CHECK_FLAGS ARGS_LEN) - if(ARGS_LEN LESS_EQUAL 0) - return() - endif() - - foreach(flag ${_CHECK_FLAGS}) - cxx_compiler_has_flag(${flag}) - if(COMPILER_FLAG_FOUND) - list(APPEND _CHECKED_FLAGS "${flag}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_FLAGS}") -endmacro() - -# -# Uses ${XA_COMMON_LINKER_FLAGS}, if defined -# -# ${EXTRA_C_LINKER_FLAGS} contains a set of additional C linker flags to check -# -# Sets VARNAME on exit -# -macro(xa_check_c_linker_flags VARNAME EXTRA_C_LINKER_FLAGS) - set(_CHECKED_FLAGS "") - set(_CHECK_FLAGS ${XA_COMMON_LINKER_FLAGS} ${EXTRA_C_LINKER_FLAGS}) - - list(LENGTH _CHECK_FLAGS ARGS_LEN) - if(ARGS_LEN LESS_EQUAL 0) - return() - endif() - - foreach(flag ${_CHECK_FLAGS}) - c_linker_has_flag(${flag}) - if(LINKER_FLAG_FOUND) - list(APPEND _CHECKED_FLAGS "${flag}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_FLAGS}") -endmacro() - -# -# Uses ${XA_COMMON_LINKER_FLAGS}, if defined -# -# ${EXTRA_CXX_LINKER_FLAGS} contains a set of additional C++ linker flags to check -# -# Sets VARNAME on exit -# -macro(xa_check_cxx_linker_flags VARNAME EXTRA_CXX_LINKER_FLAGS) - set(_CHECKED_FLAGS "") - set(_CHECK_FLAGS ${XA_COMMON_LINKER_FLAGS} ${EXTRA_CXX_LINKER_FLAGS}) - - list(LENGTH _CHECK_FLAGS ARGS_LEN) - if(ARGS_LEN LESS_EQUAL 0) - return() - endif() - - foreach(flag ${_CHECK_FLAGS}) - cxx_linker_has_flag(${flag}) - if(LINKER_FLAG_FOUND) - list(APPEND _CHECKED_FLAGS "${flag}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_FLAGS}") -endmacro() - -# -# Uses ${XA_COMMON_COMPILER_FLAGS}, if defined -# -# ${EXTRA_C_FLAGS} contains a set of additional C compiler flags to check -# ${EXTRA_CXX_FLAGS} contains a set of additional C compiler flags to check -# -# Sets VARNAME_CXX on exit -# Sets VARNAME_C on exit -# -macro(xa_check_compiler_flags VARNAME_CXX VARNAME_C EXTRA_CXX_FLAGS EXTRA_C_FLAGS) - xa_check_cxx_flags(${VARNAME_CXX} "${EXTRA_CXX_FLAGS}") - xa_check_c_flags(${VARNAME_C} "${EXTRA_C_FLAGS}") -endmacro() - -# -# Uses ${XA_COMMON_LINKER_FLAGS}, if defined -# -# ${EXTRA_C_LINKER_FLAGS} contains a set of additional C linker flags to check -# ${EXTRA_CXX_LINKER_FLAGS} contains a set of additional C++ linker flags to check -# -# Sets VARNAME_C on exit -# Sets VARNAME_CXX on exit -# -macro(xa_check_linker_flags VARNAME_CXX VARNAME_C EXTRA_CXX_LINKER_FLAGS EXTRA_C_LINKER_FLAGS) - xa_check_cxx_linker_flags(${VARNAME_CXX} "${EXTRA_CXX_LINKER_FLAGS}") - xa_check_c_linker_flags(${VARNAME_C} "${EXTRA_C_LINKER_FLAGS}") -endmacro() - -# -# Sets ${XA_COMMON_COMPILER_FLAGS} to flags that can be shared by C and C++ compilers -# Sets ${XA_COMMON_LINKER_FLAGS} to flags that can be shared by C and C++ linkers -# Sets ${XA_DEFAULT_SYMBOL_VISIBILITY} to the default symbol visibility value -# -# Defines RELEASE and NDEBUG macros for C/C++ builds if the current build type is Release -# -function(xa_common_prepare) - if(NOT DSO_SYMBOL_VISIBILITY) - set(DSO_SYMBOL_VISIBILITY "hidden") - endif() - - # - # Currently not supported by NDK clang, but worth considering when it is eventually supported: - # - # -fsanitize=safe-stack - # - - set(XA_DEFAULT_SYMBOL_VISIBILITY - -fvisibility=${DSO_SYMBOL_VISIBILITY} - PARENT_SCOPE) - - set(XA_COMMON_COMPILER_FLAGS - -fstack-protector-strong - -fstrict-return - -fno-strict-aliasing - -ffunction-sections - -funswitch-loops - -Wa,-noexecstack - -fPIC - -g - -O2 - PARENT_SCOPE - ) - - set(XA_COMMON_LINKER_FLAGS - -fstack-protector-strong - LINKER:-fstrict-return - LINKER:-z,now - LINKER:-z,relro - LINKER:-z,noexecstack - LINKER:--no-undefined - PARENT_SCOPE - ) - - if(MINGW) - list(APPEND XA_COMMON_LINKER_FLAGS - LINKER:--export-all-symbols - ) - else() - list(APPEND XA_COMMON_LINKER_FLAGS - LINKER:--export-dynamic - ) - endif() - - if(CMAKE_BUILD_TYPE STREQUAL Release) - add_compile_definitions(RELEASE NDEBUG) - endif() -endfunction() - -macro(xa_macos_prepare_arm64) - if(APPLE) - set(SDK_SUPPORTS_ARM64 False) - set(SDK_SUPPORTS_X86_64 False) - execute_process( - COMMAND xcode-select -p - RESULT_VARIABLE XCODE_SELECT_RESULT - OUTPUT_VARIABLE XCODE_DEVELOPER_PATH - ) - if(NOT ${XCODE_SELECT_RESULT} EQUAL "0") - message(WARNING "xcode-select failed with result ${XCODE_SELECT_RESULT}") - else() - string(STRIP "${XCODE_DEVELOPER_PATH}" XCODE_DEVELOPER_PATH) - set(SDKSETTINGS_PATH "${XCODE_DEVELOPER_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/SDKSettings.plist") - - # CAUTION: do NOT ever remove the '-o -' parameter, without '-o' plutil will overwrite the .plist file - execute_process( - COMMAND plutil -extract SupportedTargets.macosx.Archs json -o - "${SDKSETTINGS_PATH}" - RESULT_VARIABLE PLUTIL_RESULT - OUTPUT_VARIABLE SDK_ARCHITECTURES - ) - if(NOT ${PLUTIL_RESULT} EQUAL 0) - message(WARNING "plutil failed to read ${SDKSETTINGS_PATH}, returned with result ${PLUTIL_RESULT}") - else() - string(FIND "${SDK_ARCHITECTURES}" "\"arm64\"" ARCH_POS) - if(${ARCH_POS} GREATER_EQUAL 0) - set(SDK_SUPPORTS_ARM64 True) - endif() - - string(FIND "${SDK_ARCHITECTURES}" "\"x86_64\"" ARCH_POS) - if(${ARCH_POS} GREATER_EQUAL 0) - set(SDK_SUPPORTS_X86_64 True) - endif() - endif() - endif() - - unset(XA_OSX_ARCHITECTURES) - if(SDK_SUPPORTS_ARM64) - message(STATUS "SDK at ${XCODE_DEVELOPER_PATH} supports creation of ARM64 binaries") - set(MONOSGEN_DYLIB "${XA_LIB_TOP_DIR}/lib/host-Darwin/libmonosgen-2.0.dylib") - execute_process( - COMMAND lipo -archs ${MONOSGEN_DYLIB} - RESULT_VARIABLE LIPO_RESULT - OUTPUT_VARIABLE LIPO_OUTPUT - ) - set(ADD_ARM64 False) - if(${LIPO_RESULT} EQUAL "0") - string(FIND "${LIPO_OUTPUT}" "\"arm64\"" ARCH_POS) - if(${ARCH_POS} GREATER_EQUAL 0) - set(ADD_ARM64 True) - else() - message(WARNING "lipo reported ${MONOSGEN_DYLIB} does not contain the ARM64 image") - endif() - else() - message(WARNING "lipo check on ${MONOSGEN_DYLIB} failed with exit code ${LIPO_RESULT}") - endif() - - if(ADD_ARM64) - list(APPEND XA_OSX_ARCHITECTURES "arm64") - else() - message(WARNING "Disabling ARM64 build") - endif() - endif() - if(SDK_SUPPORTS_X86_64) - message(STATUS "SDK at ${XCODE_DEVELOPER_PATH} supports creation of X86_64 binaries") - list(APPEND XA_OSX_ARCHITECTURES "x86_64") - endif() - endif() -endmacro() diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 8982eb6f911..6ccb3fa4847 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -41,6 +41,8 @@ projects that use the Microsoft.Android framework in .NET 6+. <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so" /> <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so" /> <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-debug-app-helper.so" /> + <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-native-tracing.so" /> + <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libunwind_xamarin.a" /> diff --git a/build-tools/scripts/cmake-android.props b/build-tools/scripts/cmake-android.props new file mode 100644 index 00000000000..6335db11af8 --- /dev/null +++ b/build-tools/scripts/cmake-android.props @@ -0,0 +1,6 @@ + + + + <_CmakeAndroidFlags>--debug-output -GNinja -DCMAKE_MAKE_PROGRAM="$(NinjaPath)" -DXA_BUILD_CONFIGURATION=$(Configuration) -DXA_LIB_TOP_DIR=$(MicrosoftAndroidSdkOutDir) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DMONO_PATH="$(MonoSourceFullPath)" -DANDROID_STL="none" -DANDROID_CPP_FEATURES="no-rtti no-exceptions" -DANDROID_TOOLCHAIN=clang -DCMAKE_TOOLCHAIN_FILE="$(AndroidNdkDirectory)/build/cmake/android.toolchain.cmake" -DANDROID_NDK=$(AndroidNdkDirectory) + + diff --git a/build-tools/scripts/generate-pinvoke-tables.sh b/build-tools/scripts/generate-pinvoke-tables.sh index 9e9e26aa05e..8b683650977 100755 --- a/build-tools/scripts/generate-pinvoke-tables.sh +++ b/build-tools/scripts/generate-pinvoke-tables.sh @@ -2,7 +2,8 @@ MY_DIR="$(dirname $0)" HOST="$(uname | tr A-Z a-z)" -MONODROID_SOURCE_DIR="${MY_DIR}/../../src/monodroid/jni" +NATIVE_DIR="${MY_DIR}/../../src/native" +MONODROID_SOURCE_DIR="${NATIVE_DIR}/monodroid" 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" @@ -63,7 +64,7 @@ case ${HOST} in *) die Unsupported OS ;; esac -${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 "${GENERATOR_SOURCE}" -o "${GENERATOR_BINARY}" +${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 -I${NATIVE_DIR}/shared "${GENERATOR_SOURCE}" -o "${GENERATOR_BINARY}" "${GENERATOR_BINARY}" "${GENERATED_FILE}" FILES_DIFFER="no" diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 3166791081f..a0a532a55ab 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -204,6 +204,7 @@ public static partial class Paths public static readonly string ExternalGitDepsFilePath = Path.Combine (BuildPaths.XamarinAndroidSourceRoot, ".external"); public static readonly string ExternalGitDepsDestDir = ExternalDir; public static readonly string ExternalXamarinAndroidToolsSln = Path.Combine (ExternalDir, "xamarin-android-tools", "Xamarin.Android.Tools.sln"); + public static readonly string NativeSourcesDir = Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "src", "native"); // Dynamic locations used throughout the code public static string ExternalJavaInteropDir => GetCachedPath (ref externalJavaInteropDir, () => ctx.Properties.GetRequiredValue (KnownProperties.JavaInteropFullPath)); diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs index aaa16fb9225..e4f7d26b610 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -57,6 +57,7 @@ protected override async Task Execute (Context context) Get_SourceLink_Json (context), Get_Configuration_Generated_Props (context), Get_Cmake_XA_Build_Configuration (context), + Get_Cmake_Presets (context), }; } else { return new List { @@ -64,6 +65,7 @@ protected override async Task Execute (Context context) Get_Configuration_OperatingSystem_props (context), Get_Configuration_Generated_Props (context), Get_Cmake_XA_Build_Configuration (context), + Get_Cmake_Presets (context), Get_Ndk_projitems (context), Get_XABuildConfig_cs (context), Get_Omnisharp_Json (context), @@ -105,6 +107,30 @@ GeneratedFile Get_Cmake_XA_Build_Configuration (Context context) ); } + GeneratedFile Get_Cmake_Presets (Context context) + { + const string OutputFileName = "CMakePresets.json"; + + Properties props = context.Properties; + var replacements = new Dictionary (StringComparer.Ordinal) { + { "@AndroidNdkDirectory@", Utilities.EscapePathSeparators (props.GetRequiredValue (KnownProperties.AndroidNdkDirectory)) }, + { "@NinjaPath@", Utilities.EscapePathSeparators (props.GetRequiredValue (KnownProperties.NinjaPath)) }, + { "@MicrosoftAndroidSdkOutDir@", Utilities.EscapePathSeparators (props.GetRequiredValue (KnownProperties.MicrosoftAndroidSdkOutDir)) }, + { "@OutputPath@", Utilities.EscapePathSeparators (Path.Combine (props.GetRequiredValue (KnownProperties.MicrosoftAndroidSdkOutDir), "lib")) }, + { "@NDK_ARMEABI_V7_API_NET@", BuildAndroidPlatforms.NdkMinimumAPI.ToString () }, + { "@NDK_ARM64_V8A_API_NET@", BuildAndroidPlatforms.NdkMinimumAPI.ToString () }, + { "@NDK_X86_API_NET@", BuildAndroidPlatforms.NdkMinimumAPI.ToString () }, + { "@NDK_X86_64_API_NET@", BuildAndroidPlatforms.NdkMinimumAPI.ToString () }, + { "@XA_BUILD_CONFIGURATION@", context.Configuration }, + }; + + return new GeneratedPlaceholdersFile ( + replacements, + Path.Combine (Configurables.Paths.NativeSourcesDir, $"{OutputFileName}.in"), + Path.Combine (Configurables.Paths.NativeSourcesDir, OutputFileName) + ); + } + GeneratedFile Get_Configuration_Generated_Props (Context context) { const string OutputFileName = "Configuration.Generated.props"; diff --git a/external/libunwind b/external/libunwind new file mode 160000 index 00000000000..9cc4d98b22a --- /dev/null +++ b/external/libunwind @@ -0,0 +1 @@ +Subproject commit 9cc4d98b22ae57bc1d8c253988feb85d4298a634 diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index a0c936c59ff..da635032800 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -6,8 +6,23 @@ namespace Android.Runtime { + // Values must be identical to those in src/monodroid/jni/monodroid-glue-internal.hh + [Flags] + enum TraceKind : uint + { + Java = 0x01, + Managed = 0x02, + Native = 0x04, + Signals = 0x08, + + All = Java | Managed | Native | Signals, + } + internal static class RuntimeNativeMethods { + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] + internal extern static void monodroid_log_traces (TraceKind kind, string first_line); + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal extern static void monodroid_log (LogLevel level, LogCategories category, string message); 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 05c6c56639f..4ad281d2f17 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 @@ -214,6 +214,7 @@ _ResolveAssemblies MSBuild target. <_AndroidIncludeSystemGlobalizationNative Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' == '' ">true + <_AndroidEnableNativeStackTracing Condition=" '$(_AndroidEnableNativeStackTracing)' == ''">false <_ResolvedNativeLibraries Include="@(ResolvedFileToPublish)" Condition=" '%(ResolvedFileToPublish.Extension)' == '.so' " /> @@ -224,11 +225,12 @@ _ResolveAssemblies MSBuild target. <_MonoComponent Condition=" '$(AndroidIncludeDebugSymbols)' == 'true' " Include="debugger" /> <_MonoComponent Condition=" '$(_AndroidExcludeMarshalIlgenComponent)' != 'true' " Include="marshal-ilgen" /> - <_MonoExcludedLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" /> diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index f72d4cc5633..0191375dc54 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -11,43 +11,43 @@ "Size": 1027 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 64234 + "Size": 64231 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 91668 + "Size": 91590 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5222 + "Size": 5315 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 6548 + "Size": 6539 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 8483 + "Size": 8525 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 566421 + "Size": 570166 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 2552 + "Size": 2544 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 4025 + "Size": 4020 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 2934 + "Size": 2933 }, "lib/arm64-v8a/libarc.bin.so": { - "Size": 1512 + "Size": 1586 }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 87352 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 354064 + "Size": 476432 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3132992 + "Size": 3138768 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 67248 @@ -62,7 +62,7 @@ "Size": 155568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 12656 + "Size": 12696 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 2689557 + "PackageSize": 2742805 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index 2d232c645fb..1fff2e3e9e1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -38,127 +38,127 @@ "Size": 8090 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 72397 + "Size": 72406 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 458327 + "Size": 458238 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5222 + "Size": 5315 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { - "Size": 3998 + "Size": 3991 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 5631 + "Size": 5625 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 11520 + "Size": 11516 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { - "Size": 15413 + "Size": 15411 }, "lib/arm64-v8a/lib_System.Collections.NonGeneric.dll.so": { "Size": 7441 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { - "Size": 1941 + "Size": 1933 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 2555 + "Size": 2547 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 6089 + "Size": 6081 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 6580 + "Size": 6571 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 1976 + "Size": 1969 }, "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { - "Size": 9065 + "Size": 9060 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 6552 + "Size": 6545 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 2331 + "Size": 2325 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 1937 + "Size": 1930 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 11968 + "Size": 11963 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 11190 + "Size": 11183 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { - "Size": 15864 + "Size": 15859 }, "lib/arm64-v8a/lib_System.IO.IsolatedStorage.dll.so": { - "Size": 9897 + "Size": 9902 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 20166 + "Size": 20211 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 164751 + "Size": 164628 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 67559 + "Size": 68041 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { - "Size": 22242 + "Size": 22237 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 3594 + "Size": 3587 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 8566 + "Size": 8563 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 872867 + "Size": 874803 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 193446 + "Size": 193451 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { - "Size": 42910 + "Size": 42901 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 216089 + "Size": 215939 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 16631 + "Size": 16623 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 2709 + "Size": 2701 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 4025 + "Size": 4020 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 1865 + "Size": 1857 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 2484 + "Size": 2477 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 3758 + "Size": 3750 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 8102 + "Size": 8101 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 161398 + "Size": 161254 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 1760 + "Size": 1752 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 1776 + "Size": 1768 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 5007 @@ -233,16 +233,16 @@ "Size": 66169 }, "lib/arm64-v8a/libarc.bin.so": { - "Size": 1512 + "Size": 1586 }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 87352 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 354064 + "Size": 476432 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3132992 + "Size": 3138768 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 67248 @@ -257,7 +257,7 @@ "Size": 155568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 118880 + "Size": 118920 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -2480,5 +2480,5 @@ "Size": 812848 } }, - "PackageSize": 10218536 + "PackageSize": 10271784 } \ No newline at end of file diff --git a/src/monodroid/.gitignore b/src/monodroid/.gitignore deleted file mode 100644 index 76f4fbd0f2d..00000000000 --- a/src/monodroid/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -libs -sources.projitems diff --git a/src/monodroid/CMakeLists.txt b/src/monodroid/CMakeLists.txt deleted file mode 100644 index 85e1ec386a1..00000000000 --- a/src/monodroid/CMakeLists.txt +++ /dev/null @@ -1,562 +0,0 @@ -cmake_minimum_required(VERSION 3.18.1) - -# -# MUST be included before project()! -# -include("../../build-tools/cmake/xa_common.cmake") - -# -# Read product version -# -file(STRINGS "../../Directory.Build.props" XA_PRODUCT_VERSION_XML REGEX "^[ \t]*(.*)") -string(REGEX REPLACE "^[ \t]*(.*)" "\\1" XA_VERSION "${XA_PRODUCT_VERSION_XML}") - -project( - monodroid - VERSION ${XA_VERSION} - DESCRIPTION ".NET for Android native runtime" - HOMEPAGE_URL "https://github.com/xamarin/xamarin-android" - LANGUAGES CXX C - ) - -option(COMPILER_DIAG_COLOR "Show compiler diagnostics/errors in color" ON) - -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_C_EXTENSIONS OFF) - -if(CMAKE_BUILD_TYPE STREQUAL Debug) - set(DEBUG_BUILD True) -else() - set(DEBUG_BUILD False) -endif() - -set(XA_NO_INLINE "$ENV{XA_NO_INLINE}") -if(XA_NO_INLINE) - set(DONT_INLINE_DEFAULT ON) -else() - set(DONT_INLINE_DEFAULT OFF) -endif() - -set(XA_NO_STRIP "$ENV{XA_NO_STRIP}") -if(XA_NO_STRIP OR DEBUG_BUILD) - set(STRIP_DEBUG_DEFAULT OFF) -endif() - -option(ENABLE_CLANG_ASAN "Enable the clang AddressSanitizer support" OFF) -option(ENABLE_CLANG_UBSAN "Enable the clang UndefinedBehaviorSanitizer support" OFF) - -if(ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) - # ASAN and UBSAN always require the debug symbols to be left in the binary - set(STRIP_DEBUG_DEFAULT OFF) - set(ANALYZERS_ENABLED ON) -else() - if(NOT XA_NO_STRIP) - set(STRIP_DEBUG_DEFAULT ON) - endif() - set(ANALYZERS_ENABLED OFF) -endif() - -option(ENABLE_TIMING "Build with timing support" OFF) -option(STRIP_DEBUG "Strip debugging information when linking" ${STRIP_DEBUG_DEFAULT}) -option(DISABLE_DEBUG "Disable the built-in debugging code" OFF) -option(USE_CCACHE "Use ccache, if found, to speed up recompilation" ON) -option(DONT_INLINE "Do not inline any functions which are usually inlined, to get better stack traces" ${DONT_INLINE_DEFAULT}) - -if(USE_CCACHE) - if(CMAKE_CXX_COMPILER MATCHES "/ccache/") - message(STATUS "ccache: compiler already uses ccache") - else() - find_program(CCACHE ccache) - if(CCACHE) - set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE}") - set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE}") - message(STATUS "ccache: compiler will be lauched with ${CCACHE}") - endif() - endif() -endif() - - - -if(ANDROID_STL STREQUAL none) - set(USES_LIBSTDCPP False) -else() - set(USES_LIBSTDCPP True) -endif() - -# Environment checks - -if(NOT DEFINED MONO_PATH) - message(FATAL_ERROR "Please set the MONO_PATH variable on command line (-DMONO_PATH=PATH)") -else() - string(REPLACE "\\" "/" MONO_PATH ${MONO_PATH}) -endif() - -if(NOT DEFINED CONFIGURATION) - message(FATAL_ERROR "Please set the CONFIGURATION variable on command line (-DCONFIGURATION=name)") -endif() - -if(NOT DEFINED CMAKE_BUILD_TYPE) - message(FATAL_ERROR "Please set the CMAKE_BUILD_TYPE variable on command line (-DCMAKE_BUILD_TYPE=name)") -endif() - -if(NOT DEFINED XA_BUILD_CONFIGURATION) - message(FATAL_ERROR "Please set the XA_BUILD_CONFIGURATION variable on command line (-DXA_BUILD_CONFIGURATION=name)") -endif() - -if(NOT DEFINED XA_LIB_TOP_DIR) - message(FATAL_ERROR "Please set the XA_LIB_TOP_DIR variable on command line (-DXA_LIB_TOP_DIR=path)") -endif() - -# Needed modules - -include(CheckIncludeFile) -include(CheckCXXSymbolExists) - -# General config - -if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux) - set(IS_LINUX True) -else() - set(IS_LINUX False) -endif() - -if(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin) - set(IS_MACOS True) -else() - set(IS_MACOS False) -endif() - -# Paths - -set(EXTERNAL_DIR "../../external") -set(JAVA_INTEROP_SRC_PATH "${EXTERNAL_DIR}/Java.Interop/src/java-interop") -set(SOURCES_DIR ${CMAKE_SOURCE_DIR}/jni) -set(BIONIC_SOURCES_DIR "../../src-ThirdParty/bionic") -set(LZ4_SRC_DIR "${EXTERNAL_DIR}/lz4/lib") -set(LZ4_INCLUDE_DIR ${LZ4_SRC_DIR}) -set(XA_BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../bin/${XA_BUILD_CONFIGURATION}") -set(XA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Build${XA_BUILD_CONFIGURATION}") -set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") -set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") -set(CONSTEXPR_XXH3_DIR "${EXTERNAL_DIR}/constexpr-xxh3") - -include("${XA_BUILD_DIR}/xa_build_configuration.cmake") - -if(ANDROID_ABI MATCHES "^arm64-v8a") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM64}") -elseif(ANDROID_ABI MATCHES "^armeabi-v7a") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM}") -elseif(ANDROID_ABI MATCHES "^x86_64") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86_64}") -elseif(ANDROID_ABI MATCHES "^x86") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86}") -else() - message(FATAL "${ANDROID_ABI} is not supported for .NET 6+ builds") -endif() - -set(LZ4_SOURCES - "${LZ4_SRC_DIR}/lz4.c" - ) - -# Include directories -include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/ ${CMAKE_SOURCE_DIR}/include) -include_directories(${EXTERNAL_DIR}) - -# The SYSTEM which will make clang skip warnings for the headers there. Since we can't do -# much about them, we can just as well avoid cluttered build output. -include_directories(SYSTEM ${CONSTEXPR_XXH3_DIR}) -include_directories(SYSTEM ${ROBIN_MAP_DIR}/include) -include_directories(SYSTEM ${CMAKE_SYSROOT}/usr/include/c++/v1/) -include_directories(SYSTEM ${LZ4_INCLUDE_DIR}) -include_directories(SYSTEM "${NET_RUNTIME_DIR}/native/include/mono-2.0") -include_directories("jni") -include_directories("${XA_BIN_DIR}/include") -include_directories("${XA_BIN_DIR}/include/${ANDROID_ABI}/eglib") - -# This is to allow "release" builds with Debug build type and vice versa -include_directories("../../bin/${CONFIGURATION}/include") -include_directories("../../bin/${CONFIGURATION}/include/${ANDROID_ABI}/eglib") -include_directories("${MONO_PATH}/mono/eglib") -include_directories("${JAVA_INTEROP_SRC_PATH}") - -# Common preparation code -include("../../build-tools/cmake/xa_macros.cmake") - -xa_common_prepare() -xa_macos_prepare_arm64() - -# Compiler defines - -add_compile_definitions(XA_VERSION="${XA_VERSION}") -add_compile_definitions(TSL_NO_EXCEPTIONS) -add_compile_definitions(HAVE_CONFIG_H) -add_compile_definitions(_REENTRANT) -add_compile_definitions(JI_DLL_EXPORT) -add_compile_definitions(MONO_DLL_EXPORT) -add_compile_definitions(NET) -add_compile_definitions(JI_NO_VISIBILITY) - -if(DONT_INLINE) - add_compile_definitions(NO_INLINE) -endif() - -if(DEBUG_BUILD AND NOT DISABLE_DEBUG) - add_compile_definitions(DEBUG) -endif() - -if (ENABLE_TIMING) - add_compile_definitions(MONODROID_TIMING) -endif() - -add_compile_definitions(HAVE_LZ4) -add_compile_definitions(PLATFORM_ANDROID) - -if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") - add_compile_definitions(ANDROID64) -endif() - -if (ANDROID_NDK_MAJOR LESS 20) - add_compile_definitions(__ANDROID_API_Q__=29) -endif() - -# Compiler and linker flags -set(LINK_LIBS - -lmonosgen-2.0 - -llog -) - -# -# -Wformat-nonliteral is disabled as it's not very practical, because we use proxy functions to -# pass formats to the final Android logger functions. The Android functions have attributes that -# cause warnings similar to: -# -# warning G4FD2E6FD: format string is not a string literal [-Wformat-nonliteral] -# -# The warning is, in general, a good practice because the compiler can verify the printf format -# at compile time, but in our case it's not very useful. -# -set(LOCAL_COMMON_COMPILER_ARGS - -Wall - -Wconversion - -Wdeprecated - -Wduplicated-branches - -Wduplicated-cond - -Werror=format-security - -Werror=return-type - -Wextra - -Wformat-security - -Wformat=2 - -Wno-format-nonliteral - -Wimplicit-fallthrough - -Wmisleading-indentation - -Wnull-dereference - -Wpointer-arith - -Wshadow - -Wsign-compare - -Wtrampolines - -Wuninitialized - -fstrict-flex-arrays=3 - ) - -# Add some options to increase security. They may mildly affect performance but they won't be big, because the features are -# assisted by the hardware. -if((CMAKE_ANDROID_ARCH_ABI STREQUAL "x86") OR (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")) - # -fcf-protection=full: Enable control flow protection to counter Return Oriented Programming (ROP) and Jump Oriented Programming (JOP) attacks on many x86 architectures - list(APPEND LOCAL_COMMON_COMPILER_ARGS - -fcf-protection=full - ) -endif() - -if(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") - # -mbranch-protection=standard: Enable branch protection to counter Return Oriented Programming (ROP) and Jump Oriented Programming (JOP) attacks on AArch64 - # In clang -mbranch-protection=standard is equivalent to -mbranch-protection=bti+pac-ret and invokes the AArch64 Branch Target Identification (BTI) and Pointer Authentication using key A (pac-ret) - list(APPEND LOCAL_COMMON_COMPILER_ARGS - -mbranch-protection=standard - ) -endif() - -if(COMPILER_DIAG_COLOR) - list(APPEND LOCAL_COMMON_COMPILER_ARGS - -fdiagnostics-color=always - -fcolor-diagnostics - ) -endif() - -set(LOCAL_COMMON_LINKER_ARGS - -shared - -fpic - -fstack-clash-protection -) - -if (ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) - list(APPEND LOCAL_COMMON_COMPILER_ARGS - -fno-omit-frame-pointer - -fno-optimize-sibling-calls - ) -endif() - -unset(SANITIZER_FLAGS) -if (ENABLE_CLANG_ASAN) - set(SANITIZER_FLAGS -fsanitize=address) - set(CHECKED_BUILD_INFIX "-checked+asan") -elseif(ENABLE_CLANG_UBSAN) - set(SANITIZER_FLAGS -fsanitize=undefined) - set(CHECKED_BUILD_INFIX "-checked+ubsan") -endif() - -if(SANITIZER_FLAGS) - message(STATUS "Got sanitizer: ${SANITIZER_FLAGS}") - - list(APPEND LOCAL_COMMON_COMPILER_ARGS ${SANITIZER_FLAGS}) - list(APPEND LOCAL_COMMON_LINKER_ARGS ${SANITIZER_FLAGS}) - list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${SANITIZER_FLAGS}) -endif() - -if(STRIP_DEBUG) - list(APPEND LOCAL_COMMON_LINKER_ARGS LINKER:-S) -else() - # When not stripping symbols, we likely want to have precise stack traces, so - # we won't omit frame pointers - list(APPEND LOCAL_COMMON_COMPILER_ARGS - -fno-omit-frame-pointer - -fno-limit-debug-info - ) -endif() - -# Parameters to both functions are (all required): -# -# -# -xa_check_compiler_flags(XA_CXX_FLAGS XA_C_FLAGS "${LOCAL_COMMON_COMPILER_ARGS}" "${LOCAL_COMMON_COMPILER_ARGS}") -xa_check_linker_flags(XA_CXX_LINKER_FLAGS XA_C_LINKER_FLAGS "${LOCAL_COMMON_LINKER_ARGS}" "${LOCAL_COMMON_LINKER_ARGS}") - -add_compile_options("$<$:${XA_CXX_FLAGS}>") -add_compile_options("$<$:${XA_C_FLAGS}>") - -add_link_options("$<$:${XA_CXX_LINKER_FLAGS}>") -add_link_options("$<$:${XA_C_LINKER_FLAGS}>") - -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}) -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}") -link_directories("${NET_RUNTIME_DIR}/native") - -# Header checks - -if(ENABLE_CLANG_UBSAN OR ENABLE_CLANG_ASAN) - set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -llog") - string(STRIP "${CMAKE_REQUIRED_FLAGS}" CMAKE_REQUIRED_FLAGS) -endif() - -check_include_file("linux/netlink.h" HAVE_LINUX_NETLINK_H) -check_include_file("linux/rtnetlink.h" HAVE_LINUX_RTNETLINK_H) -check_include_file("linux/if_arp.h" HAVE_LINUX_IF_ARP_H) - -if(ENABLE_CLANG_UBSAN OR ENABLE_CLANG_ASAN) - set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") -endif() - -# Sources - -set(XAMARIN_INTERNAL_API_LIB xa-internal-api${CHECKED_BUILD_INFIX}) -set(XAMARIN_DEBUG_APP_HELPER_LIB xamarin-debug-app-helper${CHECKED_BUILD_INFIX}) -set(XAMARIN_APP_STUB_LIB xamarin-app) - -string(TOLOWER ${CMAKE_BUILD_TYPE} XAMARIN_MONO_ANDROID_SUFFIX) -set(XAMARIN_MONO_ANDROID_LIB "mono-android${CHECKED_BUILD_INFIX}.${XAMARIN_MONO_ANDROID_SUFFIX}") - -set(XAMARIN_MONODROID_SOURCES - ${JAVA_INTEROP_SRC_PATH}/java-interop-dlfcn.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop-mono.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop.cc - ${LZ4_SOURCES} - ${SOURCES_DIR}/android-system.cc - ${SOURCES_DIR}/basic-android-system.cc - ${SOURCES_DIR}/basic-utilities.cc - ${SOURCES_DIR}/cpu-arch-detect.cc - ${SOURCES_DIR}/debug-constants.cc - ${SOURCES_DIR}/debug.cc - ${SOURCES_DIR}/embedded-assemblies-zip.cc - ${SOURCES_DIR}/embedded-assemblies.cc - ${SOURCES_DIR}/globals.cc - ${SOURCES_DIR}/helpers.cc - ${SOURCES_DIR}/jni-remapping.cc - ${SOURCES_DIR}/logger.cc - ${SOURCES_DIR}/mono-log-adapter.cc - ${SOURCES_DIR}/monodroid-glue.cc - ${SOURCES_DIR}/monodroid-networkinfo.cc - ${SOURCES_DIR}/monovm-properties.cc - ${SOURCES_DIR}/new_delete.cc - ${SOURCES_DIR}/osbridge.cc - ${SOURCES_DIR}/pinvoke-override-api.cc - ${SOURCES_DIR}/shared-constants.cc - ${SOURCES_DIR}/timezones.cc - ${SOURCES_DIR}/timing-internal.cc - ${SOURCES_DIR}/util.cc - ${SOURCES_DIR}/xamarin_getifaddrs.cc -) - -if(NOT DEBUG_BUILD) - list(APPEND XAMARIN_MONODROID_SOURCES - ${SOURCES_DIR}/xamarin-android-app-context.cc - ) -endif() - -if(NOT USES_LIBSTDCPP) - list(APPEND XAMARIN_MONODROID_SOURCES - ${BIONIC_SOURCES_DIR}/cxa_guard.cc - ${SOURCES_DIR}/cxx-abi/string.cc - ${SOURCES_DIR}/cxx-abi/terminate.cc - ) -endif() - -set(XAMARIN_APP_STUB_SOURCES - ${SOURCES_DIR}/application_dso_stub.cc - ) - -set(XAMARIN_DEBUG_APP_HELPER_SOURCES - ${SOURCES_DIR}/basic-android-system.cc - ${SOURCES_DIR}/basic-utilities.cc - ${SOURCES_DIR}/cpu-arch-detect.cc - ${SOURCES_DIR}/debug-app-helper.cc - ${SOURCES_DIR}/helpers.cc - ${SOURCES_DIR}/new_delete.cc - ${SOURCES_DIR}/shared-constants.cc - ) - -set(XAMARIN_STUB_LIB_SOURCES - libstub/stub.cc -) - -# Build -configure_file(jni/host-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/host-config.h) - -add_library( - ${XAMARIN_APP_STUB_LIB} - SHARED - ${XAMARIN_APP_STUB_SOURCES} -) - -target_link_options( - ${XAMARIN_APP_STUB_LIB} - PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} -) - -set_target_properties( - ${XAMARIN_APP_STUB_LIB} - PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${XA_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}" -) - -if(DEBUG_BUILD) - add_library( - ${XAMARIN_DEBUG_APP_HELPER_LIB} - SHARED - ${XAMARIN_DEBUG_APP_HELPER_SOURCES} - ) - - target_link_options( - ${XAMARIN_DEBUG_APP_HELPER_LIB} - PRIVATE ${XA_SYMBOL_VISIBILITY} - ) - - target_link_libraries( - ${XAMARIN_DEBUG_APP_HELPER_LIB} - -ldl - ) - - target_link_libraries( - ${XAMARIN_DEBUG_APP_HELPER_LIB} - -llog - ) - - target_compile_options( - ${XAMARIN_DEBUG_APP_HELPER_LIB} - PRIVATE ${XA_SYMBOL_VISIBILITY} - ) - - target_compile_definitions( - ${XAMARIN_DEBUG_APP_HELPER_LIB} - PUBLIC -DDEBUG_APP_HELPER - ) -endif() - -add_library( - ${XAMARIN_MONO_ANDROID_LIB} - SHARED ${XAMARIN_MONODROID_SOURCES} -) - -# Ugly, but this is the only way to change LZ4 symbols visibility without modifying lz4.h -set(LZ4_VISIBILITY_OPTS "-DLZ4LIB_VISIBILITY=__attribute__ ((visibility (\"hidden\")))") - -target_compile_options( - ${XAMARIN_MONO_ANDROID_LIB} - PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} "${LZ4_VISIBILITY_OPTS}" - ) - -set(DEBUG_HELPER_LINK_LIBS "-ldl") - -target_link_options( - ${XAMARIN_MONO_ANDROID_LIB} - PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} - ) - -target_link_libraries( - ${XAMARIN_MONO_ANDROID_LIB} - ${LINK_LIBS} xamarin-app - ) - -if(NOT ANALYZERS_ENABLED) - macro(xa_add_stub_library _libname) - add_library( - ${_libname} - SHARED ${XAMARIN_STUB_LIB_SOURCES} - ) - - string(TOUPPER ${_libname} _libname_uc) - target_compile_definitions( - ${_libname} - PRIVATE STUB_LIB_NAME=lib${_libname} IN_LIB${_libname_uc} - ) - - target_compile_options( - ${_libname} - PRIVATE -nostdlib -fno-exceptions -fno-rtti - ) - - target_link_options( - ${_libname} - PRIVATE -nostdlib -fno-exceptions -fno-rtti - ) - - set_target_properties( - ${_libname} - PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${XA_LIBRARY_STUBS_OUTPUT_DIRECTORY}" - ) - endmacro() - - xa_add_stub_library(c) - xa_add_stub_library(m) - - # These two are used by the marshal methods tracing library when linking libxamarin-app.so - xa_add_stub_library(log) - xa_add_stub_library(dl) -endif() diff --git a/src/monodroid/config.xml b/src/monodroid/config.xml deleted file mode 100644 index 5c4917bbfa0..00000000000 --- a/src/monodroid/config.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/monodroid/jni/TODO.md b/src/monodroid/jni/TODO.md deleted file mode 100644 index 88c1d04ea86..00000000000 --- a/src/monodroid/jni/TODO.md +++ /dev/null @@ -1,11 +0,0 @@ -= Memory management - - * Don't use malloc and friends on pointers which aren't passed to Mono - -= Strings - - * Implement a simple class to perform all string manipulations - -= Warnings - - * Fix all the C++ warnings regarding constant strings diff --git a/src/monodroid/jni/android-system.hh b/src/monodroid/jni/android-system.hh deleted file mode 100644 index 1b62b8c74ab..00000000000 --- a/src/monodroid/jni/android-system.hh +++ /dev/null @@ -1,139 +0,0 @@ -// Dear Emacs, this is a -*- C++ -*- header -#ifndef __ANDROID_SYSTEM_H -#define __ANDROID_SYSTEM_H - -#include -#include - -#include -#include - -#include -#include - -#include "xamarin-app.hh" -#include "basic-android-system.hh" -#include "strings.hh" - -#include - -static inline constexpr size_t PROPERTY_VALUE_BUFFER_LEN = PROP_VALUE_MAX + 1; - -namespace xamarin::android { - class jstring_wrapper; - class jstring_array_wrapper; -} - -namespace xamarin::android::internal -{ -#if defined (DEBUG) - struct BundledProperty; -#endif - - class AndroidSystem : public BasicAndroidSystem - { - private: -#if defined (DEBUG) - static constexpr std::string_view OVERRIDE_ENVIRONMENT_FILE_NAME { "environment" }; - static constexpr uint32_t OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE = 22; - static BundledProperty *bundled_properties; -#endif - - public: - void setup_environment (); - void setup_process_args (jstring_array_wrapper &runtimeApks); - void create_update_dir (char *override_dir); - int monodroid_get_system_property (const char *name, char **value); - int monodroid_get_system_property (const char *name, dynamic_local_string& value); - - int monodroid_get_system_property (std::string_view const& name, char **value) noexcept - { - return monodroid_get_system_property (name.data (), value); - } - - int monodroid_get_system_property (std::string_view const& name, dynamic_local_string& value) noexcept - { - return monodroid_get_system_property (name.data (), value); - } - - size_t monodroid_get_system_property_from_overrides (const char *name, char ** value); - char* get_bundled_app (JNIEnv *env, jstring dir); - int count_override_assemblies (); - long get_gref_gc_threshold (); - void* load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check); - void* load_dso_from_any_directories (const char *name, unsigned int dl_flags); - bool get_full_dso_path_on_disk (const char *dso_name, dynamic_local_string& path); - - long get_max_gref_count () const - { - return max_gref_count; - } - - void init_max_gref_count () - { - max_gref_count = get_max_gref_count_from_system (); - } - - bool is_assembly_preload_enabled () const - { - return application_config.uses_assembly_preload; - } - - bool is_mono_llvm_enabled () const - { - return application_config.uses_mono_llvm; - } - - bool is_mono_aot_enabled () const - { - return application_config.uses_mono_aot; - } - - MonoAotMode get_mono_aot_mode () const - { - return aotMode; - } - - bool is_interpreter_enabled () const - { - return get_mono_aot_mode () == MonoAotMode::MONO_AOT_MODE_INTERP_ONLY; - } - - // Hack, see comment for `aot_mode_last_is_interpreter` at the bottom of the class declaration - bool is_aot_mode_last_really_interpreter_mode () const - { - return false; - } - - void set_running_in_emulator (bool yesno) - { - running_in_emulator = yesno; - } - - private: -#if defined (DEBUG) - void add_system_property (const char *name, const char *value); - void setup_environment (const char *name, const char *value); - void setup_environment_from_override_file (const char *path); - BundledProperty* lookup_system_property (const char *name); -#endif - const char* lookup_system_property (const char *name, size_t &value_len); - long get_max_gref_count_from_system (); - void setup_process_args_apk (const char *apk, size_t index, size_t apk_count, void *user_data); - int _monodroid__system_property_get (const char *name, char *sp_value, size_t sp_value_len); -#if defined (DEBUG) - size_t _monodroid_get_system_property_from_file (const char *path, char **value); -#endif - bool get_full_dso_path (const char *base_dir, const char *dso_path, dynamic_local_string& path); - void* load_dso_from_specified_dirs (const char **directories, size_t num_entries, const char *dso_name, unsigned int dl_flags); - void* load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags); - void* load_dso_from_override_dirs (const char *name, unsigned int dl_flags); - bool get_existing_dso_path_on_disk (const char *base_dir, const char *dso_name, dynamic_local_string& path); - - private: - long max_gref_count = 0; - MonoAotMode aotMode = MonoAotMode::MONO_AOT_MODE_NONE; - bool running_in_emulator = false; - }; -} -#endif // !__ANDROID_SYSTEM_H diff --git a/src/monodroid/jni/basic-android-system.cc b/src/monodroid/jni/basic-android-system.cc deleted file mode 100644 index e9dbbac2d0e..00000000000 --- a/src/monodroid/jni/basic-android-system.cc +++ /dev/null @@ -1,109 +0,0 @@ -#include "basic-android-system.hh" -#include "cpp-util.hh" -#include "globals.hh" - -using namespace xamarin::android; -using namespace xamarin::android::internal; - -void -BasicAndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept -{ - // appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX] points to the native library directory - std::unique_ptr libmonodroid_path {utils.path_combine (appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr (), "libmonodroid.so")}; - log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to %s", libmonodroid_path.get ()); - if (!utils.file_exists (libmonodroid_path.get ())) { - log_debug (LOG_ASSEMBLY, "%s not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); - set_embedded_dso_mode_enabled (true); - } else { - log_debug (LOG_ASSEMBLY, "Native libs extracted to %s, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - set_embedded_dso_mode_enabled (false); - } -} - -void -BasicAndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) -{ - if (!is_embedded_dso_mode_enabled ()) { - log_debug (LOG_DEFAULT, "Setting up for DSO lookup in app data directories"); - - BasicAndroidSystem::app_lib_directories = std::span (single_app_lib_directory); - BasicAndroidSystem::app_lib_directories [0] = utils.strdup_new (appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: %s", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - } else { - log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"); - - if (have_split_apks) { - // If split apks are used, then we will have just a single app library directory. Don't allocate any memory - // dynamically in this case - BasicAndroidSystem::app_lib_directories = std::span (single_app_lib_directory); - } else { - size_t app_lib_directories_size = have_split_apks ? 1 : runtimeApks.get_length (); - BasicAndroidSystem::app_lib_directories = std::span (new const char*[app_lib_directories_size], app_lib_directories_size); - } - - unsigned short built_for_cpu = 0, running_on_cpu = 0; - unsigned char is64bit = 0; - _monodroid_detect_cpu_and_architecture (&built_for_cpu, &running_on_cpu, &is64bit); - setup_apk_directories (running_on_cpu, runtimeApks, have_split_apks); - } -} - -void -BasicAndroidSystem::for_each_apk (jstring_array_wrapper &runtimeApks, ForEachApkHandler handler, void *user_data) -{ - size_t apksLength = runtimeApks.get_length (); - for (size_t i = 0; i < apksLength; ++i) { - jstring_wrapper &e = runtimeApks [i]; - - (this->*handler) (e.get_cstr (), i, apksLength, user_data); - } -} - -force_inline void -BasicAndroidSystem::add_apk_libdir (const char *apk, size_t &index, const char *abi) noexcept -{ - abort_unless (index < app_lib_directories.size (), "Index out of range"); - app_lib_directories [index] = utils.string_concat (apk, "!/lib/", abi); - log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: %s", app_lib_directories[index]); - index++; -} - -force_inline void -BasicAndroidSystem::setup_apk_directories (unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks, bool have_split_apks) noexcept -{ - const char *abi = android_abi_names [running_on_cpu]; - size_t number_of_added_directories = 0; - - for (size_t i = 0; i < runtimeApks.get_length (); ++i) { - jstring_wrapper &e = runtimeApks [i]; - const char *apk = e.get_cstr (); - - if (have_split_apks) { - if (utils.ends_with (apk, SharedConstants::split_config_abi_apk_name)) { - add_apk_libdir (apk, number_of_added_directories, abi); - break; - } - } else { - add_apk_libdir (apk, number_of_added_directories, abi); - } - } - - if (app_lib_directories.size () == number_of_added_directories) [[likely]] { - return; - } - - abort_unless (number_of_added_directories > 0, "At least a single application lib directory must be added"); - app_lib_directories = app_lib_directories.subspan (0, number_of_added_directories); -} - -char* -BasicAndroidSystem::determine_primary_override_dir (jstring_wrapper &home) -{ - dynamic_local_string name { home.get_cstr () }; - name.append ("/") - .append (SharedConstants::OVERRIDE_DIRECTORY_NAME) - .append ("/") - .append (SharedConstants::android_lib_abi); - - return utils.strdup_new (name.get ()); -} diff --git a/src/monodroid/jni/basic-android-system.hh b/src/monodroid/jni/basic-android-system.hh deleted file mode 100644 index 9b6f1bc851f..00000000000 --- a/src/monodroid/jni/basic-android-system.hh +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef __BASIC_ANDROID_SYSTEM_HH -#define __BASIC_ANDROID_SYSTEM_HH - -#include -#include -#include -#include -#include - -#include "cpu-arch.hh" -#include "jni-wrappers.hh" - -namespace xamarin::android::internal -{ - class BasicAndroidSystem - { - protected: - using ForEachApkHandler = void (BasicAndroidSystem::*) (const char *apk, size_t index, size_t apk_count, void *user_data); - - private: -#if defined (__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wc99-designator" -#endif - // Values correspond to the CPU_KIND_* macros - static constexpr const char* android_abi_names[CPU_KIND_X86_64+1] = { - [0] = "unknown", - [CPU_KIND_ARM] = "armeabi-v7a", - [CPU_KIND_ARM64] = "arm64-v8a", - [CPU_KIND_MIPS] = "mips", - [CPU_KIND_X86] = "x86", - [CPU_KIND_X86_64] = "x86_64", - }; -#if defined (__clang__) -#pragma clang diagnostic pop -#endif - static constexpr size_t ANDROID_ABI_NAMES_SIZE = sizeof(android_abi_names) / sizeof (android_abi_names[0]); - - public: -#ifdef ANDROID64 - static constexpr std::string_view SYSTEM_LIB_PATH { "/system/lib64" }; -#else - static constexpr std::string_view SYSTEM_LIB_PATH { "/system/lib" }; -#endif - - inline static std::array override_dirs{}; - - // This optimizes things a little bit. The array is allocated at build time, so we pay no cost for its - // allocation and at run time it allows us to skip dynamic memory allocation. - inline static std::array single_app_lib_directory{}; - inline static std::span app_lib_directories; - - public: - void setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks); - - void set_override_dir (uint32_t index, const char* dir) - { - if (index >= override_dirs.size ()) - return; - - override_dirs [index] = const_cast (dir); - } - - bool is_embedded_dso_mode_enabled () const - { - return embedded_dso_mode_enabled; - } - - void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; - - char *get_runtime_libdir () const - { - return runtime_libdir; - } - - void set_runtime_libdir (char *dir) - { - runtime_libdir = dir; - } - - char *get_primary_override_dir () const - { - return primary_override_dir; - } - - void set_primary_override_dir (jstring_wrapper& home) - { - primary_override_dir = determine_primary_override_dir (home); - } - - protected: - void for_each_apk (jstring_array_wrapper &runtimeApks, ForEachApkHandler handler, void *user_data); - - private: - void add_apk_libdir (const char *apk, size_t &index, const char *abi) noexcept; - void setup_apk_directories (unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks, bool have_split_apks) noexcept; - char* determine_primary_override_dir (jstring_wrapper &home); - - void set_embedded_dso_mode_enabled (bool yesno) noexcept - { - embedded_dso_mode_enabled = yesno; - } - - private: - bool embedded_dso_mode_enabled = false; - char *runtime_libdir = nullptr; - char *primary_override_dir = nullptr; - }; -} -#endif // !__BASIC_ANDROID_SYSTEM_HH diff --git a/src/monodroid/jni/basic-utilities.hh b/src/monodroid/jni/basic-utilities.hh deleted file mode 100644 index 51a42741ed0..00000000000 --- a/src/monodroid/jni/basic-utilities.hh +++ /dev/null @@ -1,343 +0,0 @@ -#ifndef __BASIC_UTILITIES_HH -#define __BASIC_UTILITIES_HH - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "java-interop-util.h" -#include "helpers.hh" -#include "cpp-util.hh" -#include "strings.hh" - -namespace xamarin::android -{ - class BasicUtilities - { - public: - FILE *monodroid_fopen (const char* filename, const char* mode); - int monodroid_dirent_hasextension (dirent *e, const char *extension); - void monodroid_strfreev (char **str_array); - char **monodroid_strsplit (const char *str, const char *delimiter, size_t max_tokens); - char *monodroid_strdup_printf (const char *format, ...); - char *monodroid_strdup_vprintf (const char *format, va_list vargs); - char* path_combine (const char *path1, const char *path2); - void create_public_directory (const char *dir); - int create_directory (const char *pathname, mode_t mode); - void set_world_accessable (const char *path); - void set_user_executable (const char *path); - bool file_exists (const char *file); - bool directory_exists (const char *directory); - bool file_copy (const char *to, const char *from); - - static std::optional get_file_size_at (int dirfd, const char *file_name) noexcept - { - struct stat sbuf; - if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, "Failed to stat file '%s': %s", file_name, std::strerror (errno)); - return {}; - } - - return static_cast(sbuf.st_size); - } - - static std::optional open_file_ro_at (int dirfd, const char *file_name) noexcept - { - int fd = openat (dirfd, file_name, O_RDONLY); - if (fd < 0) { - log_error (LOG_ASSEMBLY, "Failed to open file '%s' for reading: %s", file_name, std::strerror (errno)); - return {}; - } - - return fd; - } - - // Make sure that `buf` has enough space! This is by design, the methods are supposed to be fast. - template - void path_combine (TBuffer& buf, const char* path1, const char* path2) noexcept - { - path_combine (buf, path1, path1 == nullptr ? 0 : strlen (path1), path2, path2 == nullptr ? 0 : strlen (path2)); - } - - // internal::static_local_string - template - void path_combine (TBuffer& buf, const char* path1, size_t path1_len, const char* path2, size_t path2_len) noexcept - { - abort_unless (path1 != nullptr || path2 != nullptr, "At least one path must be a valid pointer"); - - if (path1 == nullptr) { - buf.append_c (path2); - return; - } - - if (path2 == nullptr) { - buf.append_c (path1); - return; - } - - buf.append (path1, path1_len); - buf.append ("/"); - buf.append (path2, path2_len); - } - - template - void path_combine (internal::static_local_string& buf, const char* path1, const char* path2) noexcept - { - path_combine (buf, path1, path2); - } - - template - void path_combine (internal::static_local_string& buf, const char* path1, size_t path1_len, const char* path2, size_t path2_len) noexcept - { - path_combine (buf, path1, path1_len, path2, path2_len); - } - - template - void path_combine (internal::dynamic_local_string& buf, const char* path1, const char* path2) noexcept - { - path_combine (buf, path1, path2); - } - - template - void path_combine (internal::dynamic_local_string& buf, const char* path1, size_t path1_len, const char* path2, size_t path2_len) noexcept - { - path_combine (buf, path1, path1_len, path2, path2_len); - } - - char* path_combine (const char *path1, std::string_view const& path2) noexcept - { - return path_combine (path1, path2.data ()); - } - - bool ends_with_slow (const char *str, const char *end) - { - char *p = const_cast (strstr (str, end)); - return p != nullptr && p [strlen (end)] == '\0'; - } - - template - bool ends_with (internal::dynamic_local_string const& str, std::string_view const& sv) const noexcept - { - if (str.length () < sv.length ()) { - return false; - } - - return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; - } - - template - bool ends_with (internal::dynamic_local_string& str, std::string_view const& sv) const noexcept - { - return ends_with(static_cast const&>(str), sv); - } - - bool ends_with (const char *str, std::string_view const& sv) const noexcept - { - size_t len = strlen (str); - if (len < sv.length ()) { - return false; - } - - return memcmp (str + len - sv.length (), sv.data (), sv.length ()) == 0; - } - - template - bool ends_with (const char *str, const char (&end)[N]) - { - char *p = const_cast (strstr (str, end)); - return p != nullptr && p [N - 1] == '\0'; - } - - template - bool ends_with (const char *str, std::array const& end) const noexcept - { - char *p = const_cast (strstr (str, end.data ())); - return p != nullptr && p [N - 1] == '\0'; - } - - template - bool ends_with (const char *str, helper_char_array const& end) const noexcept - { - char *p = const_cast (strstr (str, end.data ())); - return p != nullptr && p [N - 1] == '\0'; - } - - template - bool ends_with (internal::string_base const& str, const char (&end)[N]) const noexcept - { - constexpr size_t end_length = N - 1; - - size_t len = str.length (); - if (len < end_length) [[unlikely]] { - return false; - } - - return memcmp (str.get () + len - end_length, end, end_length) == 0; - } - - template - bool ends_with (internal::string_base const& str, std::array const& end) const noexcept - { - constexpr size_t end_length = N - 1; - - size_t len = str.length (); - if (len < end_length) [[unlikely]] { - return false; - } - - return memcmp (str.get () + len - end_length, end.data (), end_length) == 0; - } - - template - bool ends_with (internal::string_base const& str, helper_char_array const& end) const noexcept - { - constexpr size_t end_length = N - 1; - - size_t len = str.length (); - if (len < end_length) [[unlikely]] { - return false; - } - - return memcmp (str.get () + len - end_length, end.data (), end_length) == 0; - } - - template - const TChar* find_last (internal::string_base const& str, const char ch) const noexcept - { - if (str.empty ()) { - return nullptr; - } - - for (size_t i = str.length (); i > 0; i--) { - const size_t index = i - 1; - if (str[index] == ch) { - return str.get () + index; - } - } - - return nullptr; - } - - void *xmalloc (size_t size) - { - return ::xmalloc (size); - } - - void *xrealloc (void *ptr, size_t size) - { - return ::xrealloc (ptr, size); - } - - void *xcalloc (size_t nmemb, size_t size) - { - return ::xcalloc (nmemb, size); - } - - char *strdup_new (const char* s, size_t len) - { - if (len == 0 || s == nullptr) [[unlikely]] { - return nullptr; - } - - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, len, 1); - auto ret = new char[alloc_size]; - memcpy (ret, s, len); - ret[len] = '\0'; - - return ret; - } - - char *strdup_new (const char* s) - { - if (s == nullptr) [[unlikely]] { - return nullptr; - } - - return strdup_new (s, strlen (s)); - } - - template - char *strdup_new (internal::dynamic_local_string const& buf) noexcept - { - return strdup_new (buf.get (), buf.length ()); - } - - char *strdup_new (xamarin::android::internal::string_segment const& s, size_t from_index = 0) noexcept - { - if (from_index >= s.length ()) { - return nullptr; - } - - return strdup_new (s.start () + from_index, s.length () - from_index); - } - - template - char* string_concat (const char *s1, const CharType* s2, Strings... strings) - { - assert_char_type (); - - size_t len = calculate_length (s1, s2, strings...); - - char *ret = new char [len + 1]; - *ret = '\0'; - - concatenate_strings_into (len, ret, s1, s2, strings...); - - return ret; - } - - bool is_path_rooted (const char *path); - - template - size_t calculate_length (const CharType* s) - { - return strlen (s); - } - - template - size_t calculate_length (const CharType* s1, Strings... strings) - { - assert_char_type (); - - return strlen (s1) + calculate_length (strings...); - } - - protected: - template - void concatenate_strings_into ([[maybe_unused]] size_t len, [[maybe_unused]] char *dest) - {} - - template - void concatenate_strings_into (size_t len, char *dest, const CharType* s1, Strings... strings) - { - assert_char_type (); - - strcat (dest, s1); - concatenate_strings_into (len, dest, strings...); - } - - int make_directory (const char *path, [[maybe_unused]] mode_t mode) - { - return ::mkdir (path, mode); - } - - private: - template - static constexpr void assert_char_type () - { - static_assert (std::is_same_v, "CharType must be an 8-bit character type"); - } - }; -} -#endif // !__BASIC_UTILITIES_HH diff --git a/src/monodroid/jni/debug-constants.cc b/src/monodroid/jni/debug-constants.cc deleted file mode 100644 index 82fa9f30008..00000000000 --- a/src/monodroid/jni/debug-constants.cc +++ /dev/null @@ -1,8 +0,0 @@ -#include "debug.hh" - -using namespace xamarin::android; - -extern "C" const char *__get_debug_mono_log_property (void) -{ - return static_cast (Debug::DEBUG_MONO_LOG_PROPERTY.data ()); -} diff --git a/src/monodroid/jni/helpers.cc b/src/monodroid/jni/helpers.cc deleted file mode 100644 index e3103c04597..00000000000 --- a/src/monodroid/jni/helpers.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include "helpers.hh" - -using namespace xamarin::android; - -[[noreturn]] void -Helpers::abort_application () noexcept -{ - std::abort (); -} diff --git a/src/monodroid/jni/helpers.hh b/src/monodroid/jni/helpers.hh deleted file mode 100644 index 88d4904e92d..00000000000 --- a/src/monodroid/jni/helpers.hh +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __HELPERS_HH -#define __HELPERS_HH - -#include -#include - -#include "java-interop-util.h" -#include "platform-compat.hh" - -namespace xamarin::android -{ -#define ADD_WITH_OVERFLOW_CHECK(__ret_type__, __a__, __b__) xamarin::android::Helpers::add_with_overflow_check<__ret_type__>(__FILE__, __LINE__, (__a__), (__b__)) -#define MULTIPLY_WITH_OVERFLOW_CHECK(__ret_type__, __a__, __b__) xamarin::android::Helpers::multiply_with_overflow_check<__ret_type__>(__FILE__, __LINE__, (__a__), (__b__)) - - class Helpers - { - public: - template - force_inline static Ret add_with_overflow_check (const char *file, uint32_t line, P1 a, P2 b) noexcept - { - Ret ret; - - if (__builtin_add_overflow (a, b, &ret)) [[unlikely]] { - log_fatal (LOG_DEFAULT, "Integer overflow on addition at %s:%u", file, line); - abort_application (); - } - - return ret; - } - - // Can't use templates as above with add_with_oveflow because of a bug in the clang compiler - // shipped with the NDK: - // - // https://github.com/android-ndk/ndk/issues/294 - // https://github.com/android-ndk/ndk/issues/295 - // https://bugs.llvm.org/show_bug.cgi?id=16404 - // - // Using templated parameter types for `a` and `b` would make clang generate that tries to - // use 128-bit integers and thus output code that calls `__muloti4` and so linking would - // fail - // - template - force_inline static Ret multiply_with_overflow_check (const char *file, uint32_t line, size_t a, size_t b) noexcept - { - Ret ret; - - if (__builtin_mul_overflow (a, b, &ret)) [[unlikely]] { - log_fatal (LOG_DEFAULT, "Integer overflow on multiplication at %s:%u", file, line); - abort_application (); - } - - return ret; - } - - [[noreturn]] static void abort_application () noexcept; - }; -} -#endif // __HELPERS_HH diff --git a/src/monodroid/jni/logger.cc b/src/monodroid/jni/logger.cc deleted file mode 100644 index 581d633df99..00000000000 --- a/src/monodroid/jni/logger.cc +++ /dev/null @@ -1,331 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "logger.hh" - -#include "monodroid.h" -#include "monodroid-glue.hh" -#include "debug.hh" -#include "util.hh" -#include "globals.hh" - -#undef DO_LOG -#define DO_LOG(_level_,_category_,_format_,_args_) \ - va_start ((_args_), (_format_)); \ - __android_log_vprint ((_level_), CATEGORY_NAME((_category_)), (_format_), (_args_)); \ - va_end ((_args_)); - -using namespace xamarin::android; -using namespace xamarin::android::internal; - -// Must match the same ordering as LogCategories -static constexpr std::array log_names = { - "*none*", - "monodroid", - "monodroid-assembly", - "monodroid-debug", - "monodroid-gc", - "monodroid-gref", - "monodroid-lref", - "monodroid-timing", - "monodroid-bundle", - "monodroid-network", - "monodroid-netlink", - "*error*", -}; - -#if defined(__i386__) && defined(__GNUC__) -#define ffs(__value__) __builtin_ffs ((__value__)) -#elif defined(__x86_64__) && defined(__GNUC__) -#define ffs(__value__) __builtin_ffsll ((__value__)) -#endif - -// ffs(value) returns index of lowest bit set in `value` -#define CATEGORY_NAME(value) (value == 0 ? log_names [0] : log_names [static_cast(ffs (value))]) - -unsigned int log_categories = LOG_NONE; -unsigned int log_timing_categories; -int gc_spew_enabled; - -static FILE* -open_file (LogCategories category, const char *path, const char *override_dir, const char *filename) -{ - char *p = NULL; - FILE *f; - - if (path && access (path, W_OK) < 0) { - log_warn (category, "Could not open path '%s' for logging (\"%s\"). Using '%s/%s' instead.", - path, strerror (errno), override_dir, filename); - path = NULL; - } - - if (!path) { - utils.create_public_directory (override_dir); - p = utils.path_combine (override_dir, filename); - path = p; - } - - unlink (path); - - f = utils.monodroid_fopen (path, "a"); - - if (f) { - utils.set_world_accessable (path); - } else { - log_warn (category, "Could not open path '%s' for logging: %s", path, strerror (errno)); - } - - free (p); - - return f; -} - -static const char *gref_file = nullptr; -static const char *lref_file = nullptr; -static bool light_gref = false; -static bool light_lref = false; - -void -init_reference_logging (const char *override_dir) -{ - if ((log_categories & LOG_GREF) != 0 && !light_gref) { - gref_log = open_file (LOG_GREF, gref_file, override_dir, "grefs.txt"); - } - - if ((log_categories & LOG_LREF) != 0 && !light_lref) { - // if both lref & gref have files specified, and they're the same path, reuse the FILE*. - if (lref_file != nullptr && strcmp (lref_file, gref_file != nullptr ? gref_file : "") == 0) { - lref_log = gref_log; - } else { - lref_log = open_file (LOG_LREF, lref_file, override_dir, "lrefs.txt"); - } - } -} - -force_inline static bool -set_category (std::string_view const& name, string_segment& arg, unsigned int entry, bool arg_starts_with_name = false) -{ - if ((log_categories & entry) == entry) { - return false; - } - - if (arg_starts_with_name ? arg.starts_with (name) : arg.equal (name)) { - log_categories |= entry; - return true; - } - - return false; -} - -void -init_logging_categories (char*& mono_log_mask, char*& mono_log_level) -{ - mono_log_mask = nullptr; - mono_log_level = nullptr; - log_timing_categories = LOG_TIMING_DEFAULT; - - dynamic_local_string value; - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_LOG_PROPERTY, value) == 0) - return; - - string_segment param; - while (value.next_token (',', param)) { - constexpr std::string_view CAT_ALL { "all" }; - - if (param.equal (CAT_ALL)) { - log_categories = 0xFFFFFFFF; - break; - } - - if (set_category ("assembly", param, LOG_ASSEMBLY)) { - continue; - } - - if (set_category ("default", param, LOG_DEFAULT)) { - continue; - } - - if (set_category ("debugger", param, LOG_DEBUGGER)) { - continue; - } - - if (set_category ("gc", param, LOG_GC)) { - continue; - } - - if (set_category ("gref", param, LOG_GREF)) { - continue; - } - - if (set_category ("lref", param, LOG_LREF)) { - continue; - } - - if (set_category ("timing", param, LOG_TIMING)) { - continue; - } - - if (set_category ("network", param, LOG_NET)) { - continue; - } - - if (set_category ("netlink", param, LOG_NETLINK)) { - continue; - } - - constexpr std::string_view CAT_GREF_EQUALS { "gref=" }; - if (set_category (CAT_GREF_EQUALS, param, LOG_GREF, true /* arg_starts_with_name */)) { - gref_file = utils.strdup_new (param, CAT_GREF_EQUALS.length ()); - continue; - } - - if (set_category ("gref-", param, LOG_GREF)) { - light_gref = true; - continue; - } - - if (set_category ("gref+", param, LOG_GREF)) { - gref_to_logcat = true; - continue; - } - - constexpr std::string_view CAT_LREF_EQUALS { "lref=" }; - if (set_category (CAT_LREF_EQUALS, param, LOG_LREF, true /* arg_starts_with_name */)) { - lref_file = utils.strdup_new (param, CAT_LREF_EQUALS.length ()); - continue; - } - - if (set_category ("lref-", param, LOG_LREF)) { - light_lref = true; - continue; - } - - if (set_category ("lref+", param, LOG_LREF)) { - lref_to_logcat = true; - continue; - } - - if (param.starts_with ("timing=fast-bare")) { - log_categories |= LOG_TIMING; - log_timing_categories |= LOG_TIMING_FAST_BARE; - continue; - } - - if (param.starts_with ("timing=bare")) { - log_categories |= LOG_TIMING; - log_timing_categories |= LOG_TIMING_BARE; - continue; - } - - constexpr std::string_view MONO_LOG_MASK_ARG { "mono_log_mask=" }; - if (param.starts_with (MONO_LOG_MASK_ARG)) { - mono_log_mask = utils.strdup_new (param, MONO_LOG_MASK_ARG.length ()); - continue; - } - - constexpr std::string_view MONO_LOG_LEVEL_ARG { "mono_log_level=" }; - if (param.starts_with (MONO_LOG_LEVEL_ARG)) { - mono_log_level = utils.strdup_new (param, MONO_LOG_LEVEL_ARG.length ()); - continue; - } - -#if defined (DEBUG) - constexpr std::string_view DEBUGGER_LOG_LEVEL { "debugger-log-level=" }; - if (param.starts_with (DEBUGGER_LOG_LEVEL)) { - dynamic_local_string level; - level.assign (param.start () + DEBUGGER_LOG_LEVEL.length (), param.length () - DEBUGGER_LOG_LEVEL.length ()); - debug.set_debugger_log_level (level.get ()); - } -#endif - } - -#if DEBUG - if ((log_categories & LOG_GC) != 0) - gc_spew_enabled = 1; -#endif /* DEBUG */ -} - -void -log_error (LogCategories category, const char *format, ...) -{ - va_list args; - - DO_LOG (ANDROID_LOG_ERROR, category, format, args); -} - -void -log_fatal (LogCategories category, const char *format, ...) -{ - va_list args; - - DO_LOG (ANDROID_LOG_FATAL, category, format, args); -} - -void -log_info_nocheck (LogCategories category, const char *format, ...) -{ - va_list args; - - if ((log_categories & category) == 0) - return; - - DO_LOG (ANDROID_LOG_INFO, category, format, args); -} - -void -log_warn (LogCategories category, const char *format, ...) -{ - va_list args; - - DO_LOG (ANDROID_LOG_WARN, category, format, args); -} - -void -log_debug_nocheck (LogCategories category, const char *format, ...) -{ - va_list args; - - if ((log_categories & category) == 0) - return; - - DO_LOG (ANDROID_LOG_DEBUG, category, format, args); -} - -constexpr android_LogPriority DEFAULT_PRIORITY = ANDROID_LOG_INFO; - -// relies on the fact that the LogLevel enum has sequential values -static constexpr android_LogPriority loglevel_map[] = { - DEFAULT_PRIORITY, // Unknown - DEFAULT_PRIORITY, // Default - ANDROID_LOG_VERBOSE, // Verbose - ANDROID_LOG_DEBUG, // Debug - ANDROID_LOG_INFO, // Info - ANDROID_LOG_WARN, // Warn - ANDROID_LOG_ERROR, // Error - ANDROID_LOG_FATAL, // Fatal - ANDROID_LOG_SILENT, // Silent -}; - -static constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1; - -void -log_write (LogCategories category, LogLevel level, const char *message) noexcept -{ - size_t map_index = static_cast(level); - android_LogPriority priority; - - if (map_index > loglevel_map_max_index) { - priority = DEFAULT_PRIORITY; - } else { - priority = loglevel_map[map_index]; - } - - __android_log_write (priority, CATEGORY_NAME (category), message); -} diff --git a/src/monodroid/jni/logger.hh b/src/monodroid/jni/logger.hh deleted file mode 100644 index 81951615025..00000000000 --- a/src/monodroid/jni/logger.hh +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef __MONODROID_LOGGER_H__ -#define __MONODROID_LOGGER_H__ - -#include "java-interop-logger.h" - -void init_logging_categories (char*& mono_log_mask, char*& mono_log_level); - -void init_reference_logging (const char *override_dir); - -typedef enum _LogTimingCategories { - LOG_TIMING_DEFAULT = 0, - LOG_TIMING_BARE = 1 << 0, - LOG_TIMING_FAST_BARE = 1 << 1, -} LogTimingCategories; - -extern unsigned int log_timing_categories; - -#if DEBUG -extern int gc_spew_enabled; -#endif - -// Keep in sync with LogLevel defined in JNIEnv.cs -enum class LogLevel : unsigned int -{ - Unknown = 0x00, - Default = 0x01, - Verbose = 0x02, - Debug = 0x03, - Info = 0x04, - Warn = 0x05, - Error = 0x06, - Fatal = 0x07, - Silent = 0x08 -}; - -// A slightly faster alternative to other log functions as it doesn't parse the message -// for format placeholders nor it uses variable arguments -void log_write (LogCategories category, LogLevel level, const char *message) noexcept; -#endif diff --git a/src/monodroid/jni/util.cc b/src/monodroid/jni/util.cc deleted file mode 100644 index b7bcdd805b5..00000000000 --- a/src/monodroid/jni/util.cc +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef HAVE_BSD_STRING_H -#include -#endif - -#include -#include -#include - -#include "util.hh" -#include "globals.hh" -#include "timing-internal.hh" - -using namespace xamarin::android; -using namespace xamarin::android::internal; - -void timing_point::mark () -{ - FastTiming::get_time (sec, ns); -} - -timing_diff::timing_diff (const timing_period &period) -{ - FastTiming::calculate_interval (period.start, period.end, *this); -} - -Util::Util () -{ - page_size = getpagesize (); -} - -int -Util::send_uninterrupted (int fd, void *buf, size_t len) -{ - ssize_t res; - - do { - res = send (fd, buf, len, 0); - } while (res == -1 && errno == EINTR); - - return static_cast(res) == len; -} - -ssize_t -Util::recv_uninterrupted (int fd, void *buf, size_t len) -{ - using nbytes_type = size_t; - - ssize_t res; - size_t total = 0; - int flags = 0; - nbytes_type nbytes; - - do { - nbytes = static_cast(len - total); - res = recv (fd, (char *) buf + total, nbytes, flags); - - if (res > 0) - total += static_cast(res); - } while ((res > 0 && total < len) || (res == -1 && errno == EINTR)); - - return static_cast(total); -} - -template -inline void -Util::package_hash_to_hex (IdxType /* idx */) -{ - package_property_suffix[sizeof (package_property_suffix) / sizeof (char) - 1] = 0x00; -} - -template -inline void -Util::package_hash_to_hex (uint32_t hash, IdxType idx, Indices... indices) -{ - package_property_suffix [idx] = hex_chars [(hash & (0xF0000000 >> idx * 4)) >> ((7 - idx) * 4)]; - package_hash_to_hex (hash, indices...); -} - -void -Util::monodroid_store_package_name (const char *name) -{ - if (!name || *name == '\0') - return; - - /* Android properties can be at most 32 bytes long (!) and so we mustn't append the package name - * as-is since it will most likely generate conflicts (packages tend to be named - * com.mycompany.app), so we simply generate a hash code and use that instead. We treat the name - * as a stream of bytes assumming it's an ASCII string using a simplified version of the hash - * algorithm used by BCL's String.GetHashCode () - */ - const char *ch = name; - uint32_t hash = 0; - while (*ch) - hash = (hash << 5) - (hash + static_cast(*ch++)); - - // In C++14 or newer we could use std::index_sequence, but in C++11 it's a bit too much ado - // for this simple case, so a manual sequence it is. - // - // And yes, I know it could be done in a simple loop or in even simpler 8 lines of code, but - // that would be boring, wouldn't it? :) - package_hash_to_hex (hash, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u); - log_debug (LOG_DEFAULT, "Generated hash 0x%s for package name %s", package_property_suffix, name); -} - -MonoAssembly* -Util::monodroid_load_assembly (MonoAssemblyLoadContextGCHandle alc_handle, const char *basename) -{ - MonoImageOpenStatus status; - MonoAssemblyName *aname = mono_assembly_name_new (basename); - MonoAssembly *assm = mono_assembly_load_full_alc (alc_handle, aname, nullptr, &status); - - mono_assembly_name_free (aname); - - if (assm == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_fatal (LOG_DEFAULT, "Unable to find assembly '%s'.", basename); - Helpers::abort_application (); - } - return assm; -} - -MonoAssembly * -Util::monodroid_load_assembly (MonoDomain *domain, const char *basename) -{ - MonoAssembly *assm; - MonoAssemblyName *aname; - MonoImageOpenStatus status; - - aname = mono_assembly_name_new (basename); - MonoDomain *current = get_current_domain (); - - if (domain != current) { - mono_domain_set (domain, FALSE); - assm = mono_assembly_load_full (aname, nullptr, &status, 0); - mono_domain_set (current, FALSE); - } else { - assm = mono_assembly_load_full (aname, nullptr, &status, 0); - } - - mono_assembly_name_free (aname); - - if (!assm) { - log_fatal (LOG_DEFAULT, "Unable to find assembly '%s'.", basename); - Helpers::abort_application (); - } - return assm; -} - -MonoClass* -Util::monodroid_get_class_from_name ([[maybe_unused]] MonoDomain *domain, const char* assembly, const char *_namespace, const char *type) -{ - MonoClass *result; - MonoAssemblyName *aname = mono_assembly_name_new (assembly); - MonoAssembly *assm = mono_assembly_loaded (aname); - if (assm != nullptr) { - MonoImage *image = mono_assembly_get_image (assm); - result = mono_class_from_name (image, _namespace, type); - } else - result = nullptr; - - mono_assembly_name_free (aname); - return result; -} - -jclass -Util::get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) -{ - 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/monodroid/jni/util.hh b/src/monodroid/jni/util.hh deleted file mode 100644 index d402a01484e..00000000000 --- a/src/monodroid/jni/util.hh +++ /dev/null @@ -1,110 +0,0 @@ -// This is a -*- C++ -*- header -#ifndef __MONODROID_UTIL_H__ -#define __MONODROID_UTIL_H__ - -#ifndef TRUE -#ifdef __cplusplus -static inline constexpr int TRUE = 1; -#else -#define TRUE 1 -#endif // __cplusplus -#endif - -#ifndef FALSE -#ifdef __cplusplus -static inline constexpr int FALSE = 0; -#else -#define FALSE 0 -#endif // __cplusplus -#endif - -#include -#include -#include -#include -#include -#ifdef HAVE_BSD_STRING_H -#include -#endif -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "monodroid.h" -#include "jni-wrappers.hh" -#ifdef __cplusplus -#include "basic-utilities.hh" -#endif - -#include "java-interop-util.h" -#include "logger.hh" - -#ifdef __cplusplus -namespace xamarin::android -{ - class Util : public BasicUtilities - { - static constexpr std::array hex_chars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - static constexpr uint32_t ms_in_nsec = 1000000ULL; - - public: - Util (); - - int monodroid_getpagesize () const noexcept - { - return page_size; - } - - void monodroid_store_package_name (const char *name); - MonoAssembly *monodroid_load_assembly (MonoDomain *domain, const char *basename); - MonoAssembly *monodroid_load_assembly (MonoAssemblyLoadContextGCHandle alc_handle, const char *basename); - MonoClass *monodroid_get_class_from_name (MonoDomain *domain, const char* assembly, const char *_namespace, const char *type); - int send_uninterrupted (int fd, void *buf, size_t len); - ssize_t recv_uninterrupted (int fd, void *buf, size_t len); - jclass get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref = false); - - static bool should_log (LogCategories category) noexcept - { - return (log_categories & category) != 0; - } - - MonoDomain *get_current_domain (bool attach_thread_if_needed = true) const noexcept - { - MonoDomain *ret = mono_domain_get (); - if (ret != nullptr) { - return ret; - } - - // It's likely that we got a nullptr because the current thread isn't attached (see - // https://github.com/xamarin/xamarin-android/issues/6211), so we need to attach the thread to the root - // domain - ret = mono_get_root_domain (); - if (attach_thread_if_needed) { - mono_thread_attach (ret); - } - - return ret; - } - - private: - template - void package_hash_to_hex (IdxType idx); - - template - void package_hash_to_hex (uint32_t hash, IdxType idx, Indices... indices); - - private: - char package_property_suffix[9]; - int page_size; - }; -} -#endif // __cplusplus -#endif /* __MONODROID_UTIL_H__ */ diff --git a/src/monodroid/machine.config.xml b/src/monodroid/machine.config.xml deleted file mode 100644 index 485d8b34170..00000000000 --- a/src/monodroid/machine.config.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - -
-
-
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/native/.gitignore b/src/native/.gitignore new file mode 100644 index 00000000000..06af5ee0acd --- /dev/null +++ b/src/native/.gitignore @@ -0,0 +1,3 @@ +CMakeUserPresets.json +CMakePresets.json +static-analysis.*.txt diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt new file mode 100644 index 00000000000..3f1c6d0113d --- /dev/null +++ b/src/native/CMakeLists.txt @@ -0,0 +1,463 @@ +cmake_minimum_required(VERSION 3.21) + +# +# Read product version +# +file(STRINGS "../../Directory.Build.props" XA_PRODUCT_VERSION_XML REGEX "^[ \t]*(.*)") +string(REGEX REPLACE "^[ \t]*(.*)" "\\1" XA_VERSION "${XA_PRODUCT_VERSION_XML}") + +project( + android-native-bits + VERSION ${XA_VERSION} + DESCRIPTION ".NET for Android native runtime" + HOMEPAGE_URL "https://github.com/xamarin/xamarin-android" + LANGUAGES CXX C ASM +) + +# +# Sanity checks +# +macro(ensure_variable_set VARNAME) + if(NOT ${VARNAME}) + message(FATAL_ERROR "Variable ${VARNAME} not set. Please set it either on command line with -D${VARNAME}=value or in the presets file") + endif() +endmacro() + +ensure_variable_set(ANDROID_ABI) +ensure_variable_set(CMAKE_ANDROID_NDK) +ensure_variable_set(CMAKE_BUILD_TYPE) +ensure_variable_set(OUTPUT_PATH) +ensure_variable_set(XA_BUILD_CONFIGURATION) +ensure_variable_set(XA_LIB_TOP_DIR) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}" CACHE PATH "" FORCE) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}" CACHE PATH "" FORCE) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + +include("${CMAKE_ANDROID_NDK}/build/cmake/abis.cmake") + +if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(DEBUG_BUILD True) +else() + set(DEBUG_BUILD False) +endif() + +set(XA_NO_INLINE "$ENV{XA_NO_INLINE}") +if(XA_NO_INLINE) + set(DONT_INLINE_DEFAULT ON) +else() + set(DONT_INLINE_DEFAULT OFF) +endif() + +set(XA_NO_STRIP "$ENV{XA_NO_STRIP}") +if(XA_NO_STRIP OR DEBUG_BUILD) + set(STRIP_DEBUG_DEFAULT OFF) +endif() + +option(ENABLE_CLANG_ASAN "Enable the clang AddressSanitizer support" OFF) +option(ENABLE_CLANG_UBSAN "Enable the clang UndefinedBehaviorSanitizer support" OFF) + +if(ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) + set(STRIP_DEBUG_DEFAULT OFF) + set(ANALYZERS_ENABLED ON) +else() + if(NOT XA_NO_STRIP) + set(STRIP_DEBUG_DEFAULT ON) + endif() + set(ANALYZERS_ENABLED OFF) +endif() + +option(COMPILER_DIAG_COLOR "Show compiler diagnostics/errors in color" ON) +option(STRIP_DEBUG "Strip debugging information when linking" ${STRIP_DEBUG_DEFAULT}) +option(DISABLE_DEBUG "Disable the built-in debugging code" OFF) +option(USE_CCACHE "Use ccache, if found, to speed up recompilation" ON) +option(DONT_INLINE "Do not inline any functions which are usually inlined, to get better stack traces" ${DONT_INLINE_DEFAULT}) + +if(USE_CCACHE) + if(CMAKE_CXX_COMPILER MATCHES "/ccache/") + message(STATUS "ccache: compiler already uses ccache") + else() + find_program(CCACHE ccache) + if(CCACHE) + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE}") + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE}") + message(STATUS "ccache: compiler will be lauched with ${CCACHE}") + endif() + endif() +endif() + +if(ANDROID_STL STREQUAL none) + set(USES_LIBSTDCPP False) +else() + set(USES_LIBSTDCPP True) +endif() + +if(ANALYZERS_ENABLED) + message(STATUS "Analyzers enabled") + set(SHARED_LIB_NAME xa::shared-no-abi) +else() + message(STATUS "NO analyzers enabled") + set(SHARED_LIB_NAME xa::shared) +endif() +# +# Needed modules +# +# include(CheckIncludeFile) +# include(CheckCXXSymbolExists) +include(CheckCXXCompilerFlag) +include(CheckCCompilerFlag) +include(CheckLinkerFlag) + +# +# General config +# +set(XA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Build${XA_BUILD_CONFIGURATION}") +include("${XA_BUILD_DIR}/xa_build_configuration.cmake") + +# +# Paths +# +if(ANDROID_ABI MATCHES "^arm64-v8a") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM64}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_arm64-v8a_TRIPLE}") +elseif(ANDROID_ABI MATCHES "^armeabi-v7a") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_armeabi-v7a_TRIPLE}") +elseif(ANDROID_ABI MATCHES "^x86_64") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86_64}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_x86_64_TRIPLE}") +elseif(ANDROID_ABI MATCHES "^x86") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_x86_TRIPLE}") +else() + message(FATAL "${ANDROID_ABI} is not supported for .NET 6+ builds") +endif() + + +file(REAL_PATH "../../" REPO_ROOT_DIR) +set(EXTERNAL_DIR "${REPO_ROOT_DIR}/external") +set(JAVA_INTEROP_SRC_PATH "${EXTERNAL_DIR}/Java.Interop/src/java-interop") +set(LIBUNWIND_SOURCE_DIR "${EXTERNAL_DIR}/libunwind") + + +# +# Include directories +# +set(SYSROOT_CXX_INCLUDE_DIR ${CMAKE_SYSROOT}/usr/include/c++/v1) +set(MONO_RUNTIME_INCLUDE_DIR ${NET_RUNTIME_DIR}/native/include/mono-2.0) +set(JAVA_INTEROP_INCLUDE_DIR ${JAVA_INTEROP_SRC_PATH}) + +# +# Compiler defines +# +macro(xa_add_compile_definitions TARGET) + target_compile_definitions( + ${TARGET} + PRIVATE + XA_VERSION="${XA_VERSION}" + _REENTRANT + PLATFORM_ANDROID + ) + + if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") + target_compile_definitions( + ${TARGET} + PRIVATE + ANDROID64 + ) + endif() +endmacro() + +if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + add_compile_definitions(DEBUG) +endif() + +if(NOT DEBUG_BUILD) + add_compile_definitions(RELEASE NDEBUG) +endif() + +# +# Compiler argument macros +# +macro(_compiler_has_arg _lang _arg) + string(REGEX REPLACE "-|,|=" "_" _arg_name ${_arg}) + string(TOUPPER "${_lang}" _lang_upper) + + cmake_language(CALL check_${_lang}_compiler_flag "${_arg}" HAS_${_arg_name}_${_lang_upper}) + if(HAS_${_arg_name}_${_lang_upper}) + set(COMPILER_ARG_FOUND True) + else() + set(COMPILER_ARG_FOUND False) + endif() +endmacro() + +macro(cxx_compiler_has_arg _arg) + _compiler_has_arg(cxx ${_arg}) +endmacro() + +macro(c_compiler_has_arg _arg) + _compiler_has_arg(c ${_arg}) +endmacro() + +macro(_linker_has_arg _lang _arg) + string(REGEX REPLACE "-|,|=" "_" _arg_name ${_arg}) + string(TOUPPER "${_lang}" _lang_upper) + + check_linker_flag(${_lang} "${_arg}" HAS_${_arg_name}_LINKER_${_lang_upper}) + if(HAS_${_arg_name}_LINKER_${_lang_upper}) + set(LINKER_ARG_FOUND True) + else() + set(LINKER_ARG_FOUND False) + endif() +endmacro() + +macro(cxx_linker_has_arg _arg) + _linker_has_arg(CXX ${_arg}) +endmacro() + +macro(c_linker_has_arg _arg) + _linker_has_arg(C ${_arg}) +endmacro() + +macro(xa_check_c_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + c_compiler_has_arg(${arg}) + if(COMPILER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +macro(xa_check_cxx_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + cxx_compiler_has_arg(${arg}) + if(COMPILER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +macro(xa_check_c_linker_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + c_linker_has_arg(${arg}) + if(LINKER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +macro(xa_check_cxx_linker_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + cxx_linker_has_arg(${arg}) + if(LINKER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +set(CLANG_CHECK_SOURCES "") +macro(add_clang_check_sources SOURCES) + foreach(_source ${SOURCES}) + cmake_path(IS_RELATIVE _source _relative_path) + if(${_relative_path}) + list(APPEND _LOCAL_CLANG_CHECK_SOURCES_ ${CMAKE_CURRENT_SOURCE_DIR}/${_source}) + else() + list(APPEND _LOCAL_CLANG_CHECK_SOURCES_ ${_source}) + endif() + endforeach() + set(CLANG_CHECK_SOURCES "${_LOCAL_CLANG_CHECK_SOURCES_};${CLANG_CHECK_SOURCES}" PARENT_SCOPE) +endmacro() + +# +# Compiler args +# +set(CMAKE_CXX_VISIBILITY_PRESET "hidden") +set(CMAKE_C_VISIBILITY_PRESET "hidden") + +# +# Common flags are used when building all external +# and our own code +# +set(POTENTIAL_COMMON_COMPILER_ARGS + -fstack-protector-strong + -fstrict-return + -fno-strict-aliasing + -fno-function-sections + -fno-data-sections + -funswitch-loops + -Wa,-noexecstack + -fPIC + -g + -O2 +) + +set(POTENTIAL_COMMON_LINKER_ARGS + -fstack-protector-strong + LINKER:-fstrict-return + LINKER:-z,now + LINKER:-z,relro + LINKER:-z,noexecstack + LINKER:--no-undefined + LINKER:--export-dynamic +) + +# Add some options to increase security. They may mildly affect performance but they won't be big, because the features are +# assisted by the hardware. +if((CMAKE_ANDROID_ARCH_ABI STREQUAL "x86") OR (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")) + # -fcf-protection=full: Enable control flow protection to counter Return Oriented Programming (ROP) and Jump Oriented Programming (JOP) attacks on many x86 architectures + list(APPEND POTENTIAL_COMMON_COMPILER_ARGS + -fcf-protection=full + ) +endif() + +if(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") + # -mbranch-protection=standard: Enable branch protection to counter Return Oriented Programming (ROP) and Jump Oriented Programming (JOP) attacks on AArch64 + # In clang -mbranch-protection=standard is equivalent to -mbranch-protection=bti+pac-ret and invokes the AArch64 Branch Target Identification (BTI) and Pointer Authentication using key A (pac-ret) + list(APPEND POTENTIAL_COMMON_COMPILER_ARGS + -mbranch-protection=standard + ) +endif() + +if(COMPILER_DIAG_COLOR) + list(APPEND POTENTIAL_COMMON_COMPILER_ARGS + -fdiagnostics-color=always + -fcolor-diagnostics + ) +endif() + +if(STRIP_DEBUG) + list(APPEND POTENTIAL_COMMON_LINKER_ARGS LINKER:-S) +else() + # When not stripping symbols, we likely want to have precise stack traces, so + # we won't omit frame pointers + list(APPEND POTENTIAL_COMMON_COMPILER_ARGS + -fno-omit-frame-pointer + -fno-limit-debug-info + ) +endif() + +# +# Flags to use only when building our code +# +set(POTENTIAL_XA_COMMON_COMPILER_ARGS + -Wall + -Wconversion + -Wdeprecated + -Wduplicated-branches + -Wduplicated-cond + -Werror=format-security + -Werror=return-type + -Wextra + -Wformat-security + -Wformat=2 + -Wno-format-nonliteral + -Wimplicit-fallthrough + -Wmisleading-indentation + -Wnull-dereference + -Wpointer-arith + -Wshadow + -Wsign-compare + -Wtrampolines + -Wuninitialized + -fstrict-flex-arrays=3 +) + +if (ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) + list(APPEND POTENTIAL_XA_COMMON_COMPILER_ARGS + -fno-omit-frame-pointer + -fno-optimize-sibling-calls + ) +endif() + +set(POTENTIAL_XA_DSO_LINKER_ARGS + -fpic + -fstack-clash-protection +) + +unset(SANITIZER_FLAGS) +if (ENABLE_CLANG_ASAN) + set(SANITIZER_FLAGS -fsanitize=address) + set(CHECKED_BUILD_INFIX "-checked+asan") +elseif(ENABLE_CLANG_UBSAN) + set(SANITIZER_FLAGS -fsanitize=undefined) + set(CHECKED_BUILD_INFIX "-checked+ubsan") +endif() + +if(SANITIZER_FLAGS) + message(STATUS) + message(STATUS "Got sanitizer: ${SANITIZER_FLAGS}") + message(STATUS) + + list(APPEND POTENTIAL_XA_COMMON_COMPILER_ARGS ${SANITIZER_FLAGS}) + list(APPEND POTENTIAL_XA_COMMON_LINKER_ARGS ${SANITIZER_FLAGS}) + list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${SANITIZER_FLAGS}) +endif() + +message(STATUS) +message(STATUS "Checking support for common compiler and linker args") +message(STATUS) +xa_check_cxx_args(COMMON_CXX_ARGS "${POTENTIAL_COMMON_COMPILER_ARGS}") +xa_check_c_args(COMMON_C_ARGS "${POTENTIAL_COMMON_COMPILER_ARGS}") +xa_check_cxx_linker_args(COMMON_CXX_LINKER_ARGS "${POTENTIAL_COMMON_LINKER_ARGS}") +xa_check_c_linker_args(COMMON_C_LINKER_ARGS "${POTENTIAL_COMMON_LINKER_ARGS}") + +message(STATUS) +message(STATUS "Checking support for XA common compiler and linker args") +message(STATUS) +xa_check_cxx_args(XA_COMMON_CXX_ARGS "${POTENTIAL_XA_COMMON_COMPILER_ARGS}") +xa_check_c_args(XA_COMMON_C_ARGS "${POTENTIAL_XA_COMMON_COMPILER_ARGS}") +xa_check_cxx_linker_args(XA_COMMON_CXX_LINKER_ARGS "${POTENTIAL_XA_COMMON_LINKER_ARGS}") +xa_check_c_linker_args(XA_COMMON_C_LINKER_ARGS "${POTENTIAL_XA_COMMON_LINKER_ARGS}") +xa_check_c_linker_args(XA_C_DSO_LINKER_ARGS "${POTENTIAL_XA_DSO_LINKER_ARGS}") +xa_check_cxx_linker_args(XA_CXX_DSO_LINKER_ARGS "${POTENTIAL_XA_DSO_LINKER_ARGS}") + +add_compile_options("$<$:${COMMON_CXX_ARGS}>") +add_compile_options("$<$:${COMMON_C_ARGS}>") + +add_link_options("$<$:${COMMON_CXX_LINKER_ARGS}>") +add_link_options("$<$:${COMMON_C_LINKER_ARGS}>") + +add_subdirectory(libunwind) +add_subdirectory(lz4) +add_subdirectory(libstub) +add_subdirectory(shared) +add_subdirectory(java-interop) +add_subdirectory(xamarin-app-stub) +add_subdirectory(runtime-base) +add_subdirectory(tracing) + +if(DEBUG_BUILD) + add_subdirectory(xamarin-debug-app-helper) +endif() + +add_subdirectory(monodroid) + +add_custom_target(run_static_analysis + COMMAND ${ANDROID_TOOLCHAIN_ROOT}/bin/clang-check -analyze -p="${CMAKE_CURRENT_BINARY_DIR}" ${CLANG_CHECK_SOURCES} > ${CMAKE_SOURCE_DIR}/static-analysis.${ANDROID_ABI}.${CMAKE_BUILD_TYPE}.txt 2>&1 + COMMAND_EXPAND_LISTS + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + USES_TERMINAL +) diff --git a/src/native/CMakePresets.json.in b/src/native/CMakePresets.json.in new file mode 100644 index 00000000000..51ae5802202 --- /dev/null +++ b/src/native/CMakePresets.json.in @@ -0,0 +1,323 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + + "configurePresets": [ + { + "name": "common", + "hidden": true, + "generator": "Ninja", + "debug": { + "output": true + }, + "toolchainFile": "@AndroidNdkDirectory@/build/cmake/android.toolchain.cmake", + "cacheVariables": { + "ANDROID_NDK": "@AndroidNdkDirectory@", + "ANDROID_TOOLCHAIN": "clang", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_MAKE_PROGRAM": "@NinjaPath@", + "OUTPUT_PATH": "@OutputPath@", + "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", + "XA_BUILD_CONFIGURATION": "@XA_BUILD_CONFIGURATION@" + } + }, + + { + "name": "common-debug", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + + { + "name": "common-release", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + + { + "name": "default-common", + "hidden": true, + "inherits": "common", + "cacheVariables": { + "ANDROID_STL": "none", + "ANDROID_CPP_FEATURES": "no-rtti no-exceptions" + } + }, + + { + "name": "analyzers-common", + "hidden": true, + "inherits": "common", + "cacheVariables": { + "ANDROID_STL": "c++_static", + "ANDROID_CPP_FEATURES": "rtti exceptions" + } + }, + + { + "name": "default-debug", + "hidden": true, + "inherits": ["default-common", "common-debug"] + }, + + { + "name": "default-release", + "hidden": true, + "inherits": ["default-common", "common-release"] + }, + + { + "name": "analyzers-debug", + "hidden": true, + "inherits": ["analyzers-common", "common-debug"] + }, + + { + "name": "analyzers-release", + "hidden": true, + "inherits": ["analyzers-common", "common-release"] + }, + + { + "name": "common-armeabi-v7a", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "armeabi-v7a", + "ANDROID_NATIVE_API_LEVEL": "@NDK_ARMEABI_V7_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_ARMEABI_V7_API_NET@", + "ANDROID_RID": "android-arm" + } + }, + + { + "name": "common-arm64-v8a", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "arm64-v8a", + "ANDROID_NATIVE_API_LEVEL": "@NDK_ARM64_V8A_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_ARM64_V8A_API_NET@", + "ANDROID_RID": "android-arm64" + } + }, + + { + "name": "common-x86", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "x86", + "ANDROID_NATIVE_API_LEVEL": "@NDK_X86_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_X86_API_NET@", + "ANDROID_RID": "android-x86" + } + }, + + { + "name": "common-x86_64", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "x86_64", + "ANDROID_NATIVE_API_LEVEL": "@NDK_X86_64_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_X86_64_API_NET@", + "ANDROID_RID": "android-x64" + } + }, + + { + "name": "asan-common", + "hidden": true, + "cacheVariables": { + "ENABLE_CLANG_ASAN": "ON" + } + }, + + { + "name": "ubsan-common", + "hidden": true, + "cacheVariables": { + "ENABLE_CLANG_UBSAN": "ON" + } + }, + + { + "name": "default-debug-armeabi-v7a", + "inherits": ["default-common", "common-debug", "common-armeabi-v7a"] + }, + + { + "name": "default-release-armeabi-v7a", + "inherits": ["default-common", "common-release", "common-armeabi-v7a"] + }, + + { + "name": "analyzers-debug-armeabi-v7a", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-armeabi-v7a"] + }, + + { + "name": "analyzers-release-armeabi-v7a", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-armeabi-v7a"] + }, + + { + "name": "asan-release-armeabi-v7a", + "inherits": ["analyzers-release-armeabi-v7a", "asan-common"] + }, + + { + "name": "asan-debug-armeabi-v7a", + "inherits": ["analyzers-debug-armeabi-v7a", "asan-common"] + }, + + { + "name": "ubsan-release-armeabi-v7a", + "inherits": ["analyzers-release-armeabi-v7a", "ubsan-common"] + }, + + { + "name": "ubsan-debug-armeabi-v7a", + "inherits": ["analyzers-debug-armeabi-v7a", "ubsan-common"] + }, + + + + { + "name": "default-debug-arm64-v8a", + "inherits": ["default-common", "common-debug", "common-arm64-v8a"] + }, + + { + "name": "default-release-arm64-v8a", + "inherits": ["default-common", "common-release", "common-arm64-v8a"] + }, + + { + "name": "analyzers-debug-arm64-v8a", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-arm64-v8a"] + }, + + { + "name": "analyzers-release-arm64-v8a", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-arm64-v8a"] + }, + + { + "name": "asan-release-arm64-v8a", + "inherits": ["analyzers-release-arm64-v8a", "asan-common"] + }, + + { + "name": "asan-debug-arm64-v8a", + "inherits": ["analyzers-debug-arm64-v8a", "asan-common"] + }, + + { + "name": "ubsan-release-arm64-v8a", + "inherits": ["analyzers-release-arm64-v8a", "ubsan-common"] + }, + + { + "name": "ubsan-debug-arm64-v8a", + "inherits": ["analyzers-debug-arm64-v8a", "ubsan-common"] + }, + + + + { + "name": "default-debug-x86", + "inherits": ["default-common", "common-debug", "common-x86"] + }, + + { + "name": "default-release-x86", + "inherits": ["default-common", "common-release", "common-x86"] + }, + + { + "name": "analyzers-debug-x86", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-x86"] + }, + + { + "name": "analyzers-release-x86", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-x86"] + }, + + { + "name": "asan-release-x86", + "inherits": ["analyzers-release-x86", "asan-common"] + }, + + { + "name": "asan-debug-x86", + "inherits": ["analyzers-debug-x86", "asan-common"] + }, + + { + "name": "ubsan-release-x86", + "inherits": ["analyzers-release-x86", "ubsan-common"] + }, + + { + "name": "ubsan-debug-x86", + "inherits": ["analyzers-debug-x86", "ubsan-common"] + }, + + + + { + "name": "default-debug-x86_64", + "inherits": ["default-common", "common-debug", "common-x86_64"] + }, + + { + "name": "default-release-x86_64", + "inherits": ["default-common", "common-release", "common-x86_64"] + }, + + { + "name": "analyzers-debug-x86_64", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-x86_64"] + }, + + { + "name": "analyzers-release-x86_64", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-x86_64"] + }, + + { + "name": "asan-release-x86_64", + "inherits": ["analyzers-release-x86_64", "asan-common"] + }, + + { + "name": "asan-debug-x86_64", + "inherits": ["analyzers-debug-x86_64", "asan-common"] + }, + + { + "name": "ubsan-release-x86_64", + "inherits": ["analyzers-release-x86_64", "ubsan-common"] + }, + + { + "name": "ubsan-debug-x86_64", + "inherits": ["analyzers-debug-x86_64", "ubsan-common"] + } + ] +} diff --git a/src/native/java-interop/CMakeLists.txt b/src/native/java-interop/CMakeLists.txt new file mode 100644 index 00000000000..96510c4925f --- /dev/null +++ b/src/native/java-interop/CMakeLists.txt @@ -0,0 +1,46 @@ +set(LIB_NAME xa-java-interop) +set(LIB_ALIAS xa::java-interop) + +set(JAVA_INTEROP_SOURCES + ${JAVA_INTEROP_SRC_PATH}/java-interop-dlfcn.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop-mono.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop.cc +) +add_clang_check_sources("${JAVA_INTEROP_SOURCES}") + +add_library( + ${LIB_NAME} + STATIC + ${JAVA_INTEROP_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" +) + +target_include_directories( + ${LIB_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} +) + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} +) + +set_target_properties( + ${LIB_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native/libstub/CMakeLists.txt b/src/native/libstub/CMakeLists.txt new file mode 100644 index 00000000000..16dc744ee95 --- /dev/null +++ b/src/native/libstub/CMakeLists.txt @@ -0,0 +1,44 @@ +set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/libstubs/${ANDROID_RID}") + +set(XAMARIN_STUB_LIB_SOURCES + stub.cc +) + +macro(xa_add_stub_library _libname) + if(NOT ANALYZERS_ENABLED) + add_library( + ${_libname} + SHARED ${XAMARIN_STUB_LIB_SOURCES} + ) + + string(TOUPPER ${_libname} _libname_uc) + target_compile_definitions( + ${_libname} + PRIVATE STUB_LIB_NAME=lib${_libname} IN_LIB${_libname_uc} + ) + xa_add_compile_definitions(${_libname}) + + target_compile_options( + ${_libname} + PRIVATE ${XA_COMMON_CXX_ARGS} -nostdlib -fno-exceptions -fno-rtti + ) + + target_link_options( + ${_libname} + PRIVATE ${XA_COMMON_CXX_LINKER_ARGS} -nostdlib -fno-exceptions -fno-rtti + ) + + set_target_properties( + ${_libname} + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${XA_LIBRARY_STUBS_OUTPUT_DIRECTORY}" + ) + endif() +endmacro() + +xa_add_stub_library(c) +xa_add_stub_library(m) + +# These two are used by the marshal methods tracing library when linking libxamarin-app.so +xa_add_stub_library(log) +xa_add_stub_library(dl) diff --git a/src/monodroid/libstub/stub.cc b/src/native/libstub/stub.cc similarity index 100% rename from src/monodroid/libstub/stub.cc rename to src/native/libstub/stub.cc diff --git a/src/native/libunwind/CMakeLists.txt b/src/native/libunwind/CMakeLists.txt new file mode 100644 index 00000000000..3de53d23d34 --- /dev/null +++ b/src/native/libunwind/CMakeLists.txt @@ -0,0 +1,392 @@ +ensure_variable_set(LIBUNWIND_SOURCE_DIR) +set(LIB_NAME unwind_xamarin) +set(LIB_ALIAS xa::unwind) + +# +# Read libunwind version +# +set(CONFIGURE_AC "${LIBUNWIND_SOURCE_DIR}/configure.ac") +file(STRINGS "${CONFIGURE_AC}" UNWIND_MAJOR_VERSION_AC REGEX "^[ \t]*define[ \t]*\\([ \t]*pkg_major,[ \t]*(.*)\\)") +file(STRINGS "${CONFIGURE_AC}" UNWIND_MINOR_VERSION_AC REGEX "^[ \t]*define[ \t]*\\([ \t]*pkg_minor,[ \t]*(.*)\\)") +file(STRINGS "${CONFIGURE_AC}" UNWIND_EXTRA_VERSION_AC REGEX "^[ \t]*define[ \t]*\\([ \t]*pkg_extra,[ \t]*(.*)\\)") +string(REGEX REPLACE "^[ \t]*define[ \t]*\\([ \t]*pkg_major,[ \t]*(.*)\\)" "\\1" UNWIND_MAJOR_VERSION "${UNWIND_MAJOR_VERSION_AC}") +string(REGEX REPLACE "^[ \t]*define[ \t]*\\([ \t]*pkg_minor,[ \t]*(.*)\\)" "\\1" UNWIND_MINOR_VERSION "${UNWIND_MINOR_VERSION_AC}") +string(REGEX REPLACE "^[ \t]*define[ \t]*\\([ \t]*pkg_extra,[ \t]*(.*)\\)" "\\1" UNWIND_EXTRA_VERSION "${UNWIND_EXTRA_VERSION_AC}") + +set(PKG_MAJOR "${UNWIND_MAJOR_VERSION}") +set(PKG_MINOR "${UNWIND_MINOR_VERSION}") +set(PKG_EXTRA "${UNWIND_EXTRA_VERSION}") +set(PACKAGE_STRING "libunwind-xamarin") +set(PACKAGE_BUGREPORT "") + +message(STATUS "libunwind version: ${PKG_MAJOR}.${PKG_MINOR}.${PKG_EXTRA}") + +include(CheckCSourceCompiles) +include(CheckIncludeFiles) +include(CheckSymbolExists) + +if(CMAKE_ANDROID_ARCH_ABI STREQUAL arm64-v8a) + set(TARGET_AARCH64 TRUE) + set(arch aarch64) +elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL armeabi-v7a) + set(TARGET_ARM TRUE) + set(arch arm) +elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL x86_64) + set(TARGET_AMD64 TRUE) + set(arch x86_64) +elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL x86) + set(TARGET_X86 TRUE) + set(arch x86) +else() + message(FATAL_ERROR "Unsupported Android ABI ${CMAKE_ANDROID_ARCH_ABI}") +endif() + +if(IS_DEBUG) + list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS -g -fno-omit-frame-pointer) +else() + list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS -fomit-frame-pointer) + add_compile_definitions(NDEBUG) +endif() +list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS + -fno-asynchronous-unwind-tables + -fno-unwind-tables + + # Turn off some warnings, as we can't do much about them here... + -Wno-absolute-value + -Wno-incompatible-pointer-types + -Wno-macro-redefined + -Wno-sign-conversion + -Wno-single-bit-bitfield-constant-conversion + -Wno-tautological-constant-out-of-range-compare +) + +xa_check_c_args(LIBUNWIND_C_ARGS "${POTENTIAL_LOCAL_COMPILER_ARGS}") + +# Detect include files +set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) + +set(HAVE_ASM_VSYSCALL_H True) +#check_include_files(asm/vsyscall.h HAVE_ASM_VSYSCALL_H) +check_include_files(byteswap.h HAVE_BYTESWAP_H) +check_include_files(elf.h HAVE_ELF_H) +check_include_files(endian.h HAVE_ENDIAN_H) +check_include_files(link.h HAVE_LINK_H) +check_include_files(sys/endian.h HAVE_SYS_ENDIAN_H) +check_include_files(sys/link.h HAVE_SYS_LINK_H) +check_include_files(sys/param.h HAVE_SYS_PARAM_H) +check_include_files(sys/syscall.h HAVE_SYS_SYSCALL_H) + +# Detect functions +check_symbol_exists(mincore "sys/mman.h" HAVE_MINCORE) +check_symbol_exists(pipe2 "fcntl.h;unistd.h" HAVE_PIPE2) + +# TODO: consider enabling zlib + +configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) +configure_file(${LIBUNWIND_SOURCE_DIR}/include/libunwind-common.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind-common.h) +configure_file(${LIBUNWIND_SOURCE_DIR}/include/libunwind.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind.h) +configure_file(${LIBUNWIND_SOURCE_DIR}/include/tdep/libunwind_i.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/tdep/libunwind_i.h) + +set(SOURCES_DIR ${LIBUNWIND_SOURCE_DIR}/src) + +set(LIBUNWIND_XAMARIN_SOURCES + ${SOURCES_DIR}/dwarf/Gexpr.c + ${SOURCES_DIR}/dwarf/Gfde.c + ${SOURCES_DIR}/dwarf/Gfind_proc_info-lsb.c + ${SOURCES_DIR}/dwarf/Gfind_unwind_table.c + ${SOURCES_DIR}/dwarf/Gget_proc_info_in_range.c + ${SOURCES_DIR}/dwarf/Gparser.c + ${SOURCES_DIR}/dwarf/Gpe.c + ${SOURCES_DIR}/dwarf/Lexpr.c + ${SOURCES_DIR}/dwarf/Lfde.c + ${SOURCES_DIR}/dwarf/Lfind_proc_info-lsb.c + ${SOURCES_DIR}/dwarf/Lfind_unwind_table.c + ${SOURCES_DIR}/dwarf/Lget_proc_info_in_range.c + ${SOURCES_DIR}/dwarf/Lparser.c + ${SOURCES_DIR}/dwarf/Lpe.c + ${SOURCES_DIR}/dwarf/global.c + ${SOURCES_DIR}/elfxx.c + ${SOURCES_DIR}/mi/Gaddress_validator.c + ${SOURCES_DIR}/mi/Gdestroy_addr_space.c + ${SOURCES_DIR}/mi/Gdyn-extract.c +# ${SOURCES_DIR}/mi/Gdyn-remote.c + ${SOURCES_DIR}/mi/Gfind_dynamic_proc_info.c + ${SOURCES_DIR}/mi/Gget_elf_filename.c + ${SOURCES_DIR}/mi/Gget_fpreg.c + ${SOURCES_DIR}/mi/Gget_proc_info_by_ip.c + ${SOURCES_DIR}/mi/Gget_proc_name.c + ${SOURCES_DIR}/mi/Gget_reg.c + ${SOURCES_DIR}/mi/Gput_dynamic_unwind_info.c + ${SOURCES_DIR}/mi/Gset_cache_size.c + ${SOURCES_DIR}/mi/Gset_caching_policy.c + ${SOURCES_DIR}/mi/Gset_fpreg.c + ${SOURCES_DIR}/mi/Gset_iterate_phdr_function.c + ${SOURCES_DIR}/mi/Gset_reg.c + ${SOURCES_DIR}/mi/Ldestroy_addr_space.c + ${SOURCES_DIR}/mi/Ldyn-extract.c + ${SOURCES_DIR}/mi/Lfind_dynamic_proc_info.c + ${SOURCES_DIR}/mi/Lget_accessors.c + ${SOURCES_DIR}/mi/Lget_elf_filename.c + ${SOURCES_DIR}/mi/Lget_fpreg.c + ${SOURCES_DIR}/mi/Lget_proc_info_by_ip.c + ${SOURCES_DIR}/mi/Lget_proc_name.c + ${SOURCES_DIR}/mi/Lget_reg.c + ${SOURCES_DIR}/mi/Lput_dynamic_unwind_info.c + ${SOURCES_DIR}/mi/Lset_cache_size.c + ${SOURCES_DIR}/mi/Lset_caching_policy.c + ${SOURCES_DIR}/mi/Lset_fpreg.c + ${SOURCES_DIR}/mi/Lset_iterate_phdr_function.c + ${SOURCES_DIR}/mi/Lset_reg.c + ${SOURCES_DIR}/mi/backtrace.c + ${SOURCES_DIR}/mi/dyn-cancel.c + ${SOURCES_DIR}/mi/dyn-info-list.c + ${SOURCES_DIR}/mi/dyn-register.c + ${SOURCES_DIR}/mi/flush_cache.c + ${SOURCES_DIR}/mi/init.c + ${SOURCES_DIR}/mi/mempool.c + ${SOURCES_DIR}/mi/strerror.c + ${SOURCES_DIR}/os-linux.c +) + +if(TARGET_AMD64 OR TARGET_AARCH64) + list(APPEND LIBUNWIND_XAMARIN_SOURCES + ${SOURCES_DIR}/elf64.c + ) +endif() + +if(TARGET_X86 OR TARGET_ARM) + list(APPEND LIBUNWIND_XAMARIN_SOURCES + ${SOURCES_DIR}/elf32.c + ) +endif() + +if(TARGET_X86) + list(APPEND LIBUNWIND_XAMARIN_SOURCES + ${SOURCES_DIR}/x86/Gapply_reg_state.c + ${SOURCES_DIR}/x86/Gcreate_addr_space.c + ${SOURCES_DIR}/x86/Gget_proc_info.c + ${SOURCES_DIR}/x86/Gget_save_loc.c + ${SOURCES_DIR}/x86/Gglobal.c + ${SOURCES_DIR}/x86/Ginit.c + ${SOURCES_DIR}/x86/Ginit_local.c + ${SOURCES_DIR}/x86/Ginit_remote.c + ${SOURCES_DIR}/x86/Gos-linux.c + ${SOURCES_DIR}/x86/Greg_states_iterate.c + ${SOURCES_DIR}/x86/Gregs.c + ${SOURCES_DIR}/x86/Gresume.c + ${SOURCES_DIR}/x86/Gstep.c + ${SOURCES_DIR}/x86/Lapply_reg_state.c + ${SOURCES_DIR}/x86/Lcreate_addr_space.c + ${SOURCES_DIR}/x86/Lget_proc_info.c + ${SOURCES_DIR}/x86/Lget_save_loc.c + ${SOURCES_DIR}/x86/Lglobal.c + ${SOURCES_DIR}/x86/Linit.c + ${SOURCES_DIR}/x86/Linit_local.c + ${SOURCES_DIR}/x86/Linit_remote.c + ${SOURCES_DIR}/x86/Los-linux.c + ${SOURCES_DIR}/x86/Lreg_states_iterate.c + ${SOURCES_DIR}/x86/Lregs.c + ${SOURCES_DIR}/x86/Lresume.c + ${SOURCES_DIR}/x86/Lstep.c + ${SOURCES_DIR}/x86/getcontext-linux.S + ${SOURCES_DIR}/x86/is_fpreg.c + ${SOURCES_DIR}/x86/regname.c + ) +endif(TARGET_X86) + +if(TARGET_AMD64) + list(APPEND LIBUNWIND_XAMARIN_SOURCES + ${SOURCES_DIR}/x86_64/Gapply_reg_state.c + ${SOURCES_DIR}/x86_64/Gcreate_addr_space.c + ${SOURCES_DIR}/x86_64/Gget_proc_info.c + ${SOURCES_DIR}/x86_64/Gget_save_loc.c + ${SOURCES_DIR}/x86_64/Gglobal.c + ${SOURCES_DIR}/x86_64/Ginit.c + ${SOURCES_DIR}/x86_64/Ginit_local.c + ${SOURCES_DIR}/x86_64/Ginit_remote.c + ${SOURCES_DIR}/x86_64/Gos-linux.c + ${SOURCES_DIR}/x86_64/Greg_states_iterate.c + ${SOURCES_DIR}/x86_64/Gregs.c + ${SOURCES_DIR}/x86_64/Gresume.c + ${SOURCES_DIR}/x86_64/Gstash_frame.c + ${SOURCES_DIR}/x86_64/Gstep.c + ${SOURCES_DIR}/x86_64/Gtrace.c + ${SOURCES_DIR}/x86_64/Lapply_reg_state.c + ${SOURCES_DIR}/x86_64/Lcreate_addr_space.c + ${SOURCES_DIR}/x86_64/Lget_proc_info.c + ${SOURCES_DIR}/x86_64/Lget_save_loc.c + ${SOURCES_DIR}/x86_64/Lglobal.c + ${SOURCES_DIR}/x86_64/Linit.c + ${SOURCES_DIR}/x86_64/Linit_local.c + ${SOURCES_DIR}/x86_64/Linit_remote.c + ${SOURCES_DIR}/x86_64/Los-linux.c + ${SOURCES_DIR}/x86_64/Lreg_states_iterate.c + ${SOURCES_DIR}/x86_64/Lregs.c + ${SOURCES_DIR}/x86_64/Lresume.c + ${SOURCES_DIR}/x86_64/Lstash_frame.c + ${SOURCES_DIR}/x86_64/Lstep.c + ${SOURCES_DIR}/x86_64/Ltrace.c + ${SOURCES_DIR}/x86_64/getcontext.S + ${SOURCES_DIR}/x86_64/is_fpreg.c + ${SOURCES_DIR}/x86_64/regname.c + ${SOURCES_DIR}/x86_64/setcontext.S + ) +endif() + +if(TARGET_ARM) + list(APPEND LIBUNWIND_XAMARIN_SOURCES + ${SOURCES_DIR}/arm/Gapply_reg_state.c + ${SOURCES_DIR}/arm/Gcreate_addr_space.c + ${SOURCES_DIR}/arm/Gex_tables.c + ${SOURCES_DIR}/arm/Gget_proc_info.c + ${SOURCES_DIR}/arm/Gget_save_loc.c + ${SOURCES_DIR}/arm/Gglobal.c + ${SOURCES_DIR}/arm/Ginit.c + ${SOURCES_DIR}/arm/Ginit_local.c + ${SOURCES_DIR}/arm/Ginit_remote.c + ${SOURCES_DIR}/arm/Gos-linux.c + ${SOURCES_DIR}/arm/Greg_states_iterate.c + ${SOURCES_DIR}/arm/Gregs.c + ${SOURCES_DIR}/arm/Gresume.c + ${SOURCES_DIR}/arm/Gstash_frame.c + ${SOURCES_DIR}/arm/Gstep.c + ${SOURCES_DIR}/arm/Gtrace.c + ${SOURCES_DIR}/arm/Lapply_reg_state.c + ${SOURCES_DIR}/arm/Lcreate_addr_space.c + ${SOURCES_DIR}/arm/Lex_tables.c + ${SOURCES_DIR}/arm/Lget_proc_info.c + ${SOURCES_DIR}/arm/Lget_save_loc.c + ${SOURCES_DIR}/arm/Lglobal.c + ${SOURCES_DIR}/arm/Linit.c + ${SOURCES_DIR}/arm/Linit_local.c + ${SOURCES_DIR}/arm/Linit_remote.c + ${SOURCES_DIR}/arm/Los-linux.c + ${SOURCES_DIR}/arm/Lreg_states_iterate.c + ${SOURCES_DIR}/arm/Lregs.c + ${SOURCES_DIR}/arm/Lresume.c + ${SOURCES_DIR}/arm/Lstash_frame.c + ${SOURCES_DIR}/arm/Lstep.c + ${SOURCES_DIR}/arm/Ltrace.c + ${SOURCES_DIR}/arm/getcontext.S + ${SOURCES_DIR}/arm/is_fpreg.c + ${SOURCES_DIR}/arm/regname.c + ) +endif() + +if(TARGET_AARCH64) + list(APPEND LIBUNWIND_XAMARIN_SOURCES + ${SOURCES_DIR}/aarch64/Gapply_reg_state.c + ${SOURCES_DIR}/aarch64/Gcreate_addr_space.c + ${SOURCES_DIR}/aarch64/Gget_proc_info.c + ${SOURCES_DIR}/aarch64/Gget_save_loc.c + ${SOURCES_DIR}/aarch64/Gglobal.c + ${SOURCES_DIR}/aarch64/Ginit.c + ${SOURCES_DIR}/aarch64/Ginit_local.c + ${SOURCES_DIR}/aarch64/Ginit_remote.c + ${SOURCES_DIR}/aarch64/Gis_signal_frame.c + + # Use local version with partial revert of https://github.com/libunwind/libunwind/pull/503 + # until https://github.com/libunwind/libunwind/issues/702 is fixed + # ${SOURCES_DIR}/aarch64/Gos-linux.c + fixes/aarch64/Gos-linux.c + + ${SOURCES_DIR}/aarch64/Greg_states_iterate.c + ${SOURCES_DIR}/aarch64/Gregs.c + ${SOURCES_DIR}/aarch64/Gresume.c + ${SOURCES_DIR}/aarch64/Gstash_frame.c + ${SOURCES_DIR}/aarch64/Gstep.c + ${SOURCES_DIR}/aarch64/Gtrace.c + ${SOURCES_DIR}/aarch64/Lapply_reg_state.c + ${SOURCES_DIR}/aarch64/Lcreate_addr_space.c + ${SOURCES_DIR}/aarch64/Lget_proc_info.c + ${SOURCES_DIR}/aarch64/Lget_save_loc.c + ${SOURCES_DIR}/aarch64/Lglobal.c + ${SOURCES_DIR}/aarch64/Linit.c + ${SOURCES_DIR}/aarch64/Linit_local.c + ${SOURCES_DIR}/aarch64/Linit_remote.c + ${SOURCES_DIR}/aarch64/Lis_signal_frame.c + ${SOURCES_DIR}/aarch64/Lreg_states_iterate.c + ${SOURCES_DIR}/aarch64/Lregs.c + ${SOURCES_DIR}/aarch64/Lresume.c + ${SOURCES_DIR}/aarch64/Lstash_frame.c + ${SOURCES_DIR}/aarch64/Lstep.c + ${SOURCES_DIR}/aarch64/Ltrace.c + ${SOURCES_DIR}/aarch64/getcontext.S + ${SOURCES_DIR}/aarch64/is_fpreg.c + ${SOURCES_DIR}/aarch64/regname.c + ) +endif() + +add_library( + ${LIB_NAME} + STATIC + ${LIBUNWIND_XAMARIN_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +list(APPEND LIBUNWIND_INCLUDE_DIRS + ${LIBUNWIND_SOURCE_DIR}/include/tdep + ${LIBUNWIND_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include/tdep + ${CMAKE_CURRENT_BINARY_DIR}/include +) +set(LIBUNWIND_INCLUDE_DIRS "${LIBUNWIND_INCLUDE_DIRS}" PARENT_SCOPE) + +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" +) + +if(TARGET_ARM) + # Ensure that the remote and local unwind code can reside in the same binary without name clashing + target_compile_definitions( + ${LIB_NAME} + PRIVATE + "arm_search_unwind_table=UNW_OBJ(arm_search_unwind_table)" + ) + + # We compile code with -std=c99 and the asm keyword is not recognized as it is a gnu extension + #TODO: possibly not needed? add_definitions(-Dasm=__asm__) + # The arm sources include ex_tables.h from include/tdep-arm without going through a redirection + # in include/tdep like it works for similar files on other architectures. So we need to add + # the include/tdep-arm to include directories + target_include_directories( + ${LIB_NAME} + PRIVATE + ${LIBUNWIND_SOURCE_DIR}/include/tdep-arm + ) +elseif(TARGET_AARCH64) + # We compile code with -std=c99 and the asm keyword is not recognized as it is a gnu extension + #TODO: possibly not needed? add_definitions(-Dasm=__asm__) +endif() + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${COMMON_C_ARGS} ${LIBUNWIND_C_ARGS} +) + +target_include_directories( + ${LIB_NAME} + PRIVATE + ${LIBUNWIND_SOURCE_DIR}/src +) + +target_link_options( + ${LIB_NAME} + PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} +) + +target_compile_definitions( + ${LIB_NAME} + PUBLIC + UNW_LOCAL_ONLY +) + +target_compile_definitions( + ${LIB_NAME} + PRIVATE + HAVE_CONFIG_H _GNU_SOURCE +) diff --git a/src/native/libunwind/config.h.in b/src/native/libunwind/config.h.in new file mode 100644 index 00000000000..52656bb9740 --- /dev/null +++ b/src/native/libunwind/config.h.in @@ -0,0 +1,21 @@ +#if !defined (__LIBUNWIND_CONFIG_H) +#define __LIBUNWIND_CONFIG_H + +#cmakedefine01 HAVE_ELF_H +#cmakedefine01 HAVE_ENDIAN_H +#cmakedefine01 HAVE_ASM_VSYSCALL_H +#cmakedefine01 HAVE_BYTESWAP_H +#cmakedefine01 HAVE_ELF_H +#cmakedefine01 HAVE_ENDIAN_H +#cmakedefine01 HAVE_LINK_H +#cmakedefine01 HAVE_SYS_ENDIAN_H +#cmakedefine01 HAVE_SYS_LINK_H +#cmakedefine01 HAVE_SYS_PARAM_H +#cmakedefine01 HAVE_SYS_SYSCALL_H +#cmakedefine01 HAVE_MINCORE +#cmakedefine01 HAVE_PIPE2 + +#define PACKAGE_STRING "@PACKAGE_STRING@" +#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +#endif // ndef __LIBUNWIND_CONFIG_H diff --git a/src/native/libunwind/fixes/aarch64/Gos-linux.c b/src/native/libunwind/fixes/aarch64/Gos-linux.c new file mode 100644 index 00000000000..fd9f266427c --- /dev/null +++ b/src/native/libunwind/fixes/aarch64/Gos-linux.c @@ -0,0 +1,145 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 CodeSourcery + Copyright (C) 2011-2013 Linaro Limited + Copyright (C) 2012 Tommi Rantala + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +//#include "unwind_i.h" +#include "../../../../external/libunwind/src/aarch64/unwind_i.h" +#ifndef UNW_REMOTE_ONLY + +HIDDEN int +aarch64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) +{ + struct cursor *c = (struct cursor *) cursor; + unw_tdep_context_t *uc = c->uc; + + if (c->sigcontext_format == AARCH64_SCF_NONE) + { + /* Since there are no signals involved here we restore EH and non scratch + registers only. */ + unsigned long regs[24]; + regs[0] = uc->uc_mcontext.regs[0]; + regs[1] = uc->uc_mcontext.regs[1]; + regs[2] = uc->uc_mcontext.regs[2]; + regs[3] = uc->uc_mcontext.regs[3]; + regs[4] = uc->uc_mcontext.regs[19]; + regs[5] = uc->uc_mcontext.regs[20]; + regs[6] = uc->uc_mcontext.regs[21]; + regs[7] = uc->uc_mcontext.regs[22]; + regs[8] = uc->uc_mcontext.regs[23]; + regs[9] = uc->uc_mcontext.regs[24]; + regs[10] = uc->uc_mcontext.regs[25]; + regs[11] = uc->uc_mcontext.regs[26]; + regs[12] = uc->uc_mcontext.regs[27]; + regs[13] = uc->uc_mcontext.regs[28]; + regs[14] = uc->uc_mcontext.regs[29]; /* FP */ + regs[15] = uc->uc_mcontext.regs[30]; /* LR */ + regs[16] = GET_FPCTX(uc)->vregs[8]; + regs[17] = GET_FPCTX(uc)->vregs[9]; + regs[18] = GET_FPCTX(uc)->vregs[10]; + regs[19] = GET_FPCTX(uc)->vregs[11]; + regs[20] = GET_FPCTX(uc)->vregs[12]; + regs[21] = GET_FPCTX(uc)->vregs[13]; + regs[22] = GET_FPCTX(uc)->vregs[14]; + regs[23] = GET_FPCTX(uc)->vregs[15]; + unsigned long sp = uc->uc_mcontext.sp; + + struct regs_overlay { + char x[sizeof(regs)]; + }; + + __asm__ __volatile__ ( + "mov x4, %0\n" + "mov x5, %1\n" + "ldp x0, x1, [x4]\n" + "ldp x2, x3, [x4,16]\n" + "ldp x19, x20, [x4,32]\n" + "ldp x21, x22, [x4,48]\n" + "ldp x23, x24, [x4,64]\n" + "ldp x25, x26, [x4,80]\n" + "ldp x27, x28, [x4,96]\n" + "ldp x29, x30, [x4,112]\n" + "ldp d8, d9, [x4,128]\n" + "ldp d10, d11, [x4,144]\n" + "ldp d12, d13, [x4,160]\n" + "ldp d14, d15, [x4,176]\n" + "mov sp, x5\n" + "ret \n" + : + : "r" (regs), + "r" (sp), + "m" (*(struct regs_overlay *)regs) + ); + } + else + { + struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; + + if (c->dwarf.eh_valid_mask & 0x1) sc->regs[0] = c->dwarf.eh_args[0]; + if (c->dwarf.eh_valid_mask & 0x2) sc->regs[1] = c->dwarf.eh_args[1]; + if (c->dwarf.eh_valid_mask & 0x4) sc->regs[2] = c->dwarf.eh_args[2]; + if (c->dwarf.eh_valid_mask & 0x8) sc->regs[3] = c->dwarf.eh_args[3]; + + sc->regs[4] = uc->uc_mcontext.regs[4]; + sc->regs[5] = uc->uc_mcontext.regs[5]; + sc->regs[6] = uc->uc_mcontext.regs[6]; + sc->regs[7] = uc->uc_mcontext.regs[7]; + sc->regs[8] = uc->uc_mcontext.regs[8]; + sc->regs[9] = uc->uc_mcontext.regs[9]; + sc->regs[10] = uc->uc_mcontext.regs[10]; + sc->regs[11] = uc->uc_mcontext.regs[11]; + sc->regs[12] = uc->uc_mcontext.regs[12]; + sc->regs[13] = uc->uc_mcontext.regs[13]; + sc->regs[14] = uc->uc_mcontext.regs[14]; + sc->regs[15] = uc->uc_mcontext.regs[15]; + sc->regs[16] = uc->uc_mcontext.regs[16]; + sc->regs[17] = uc->uc_mcontext.regs[17]; + sc->regs[18] = uc->uc_mcontext.regs[18]; + sc->regs[19] = uc->uc_mcontext.regs[19]; + sc->regs[20] = uc->uc_mcontext.regs[20]; + sc->regs[21] = uc->uc_mcontext.regs[21]; + sc->regs[22] = uc->uc_mcontext.regs[22]; + sc->regs[23] = uc->uc_mcontext.regs[23]; + sc->regs[24] = uc->uc_mcontext.regs[24]; + sc->regs[25] = uc->uc_mcontext.regs[25]; + sc->regs[26] = uc->uc_mcontext.regs[26]; + sc->regs[27] = uc->uc_mcontext.regs[27]; + sc->regs[28] = uc->uc_mcontext.regs[28]; + sc->regs[29] = uc->uc_mcontext.regs[29]; + sc->regs[30] = uc->uc_mcontext.regs[30]; + sc->sp = uc->uc_mcontext.sp; + sc->pc = uc->uc_mcontext.pc; + sc->pstate = uc->uc_mcontext.pstate; + + __asm__ __volatile__ ( + "mov sp, %0\n" + "ret %1\n" + : : "r" (c->sigcontext_sp), "r" (c->sigcontext_pc) + ); + } + unreachable(); + return -UNW_EINVAL; +} + +#endif /* !UNW_REMOTE_ONLY */ diff --git a/src/native/libunwind/libunwind-xamarin.csproj b/src/native/libunwind/libunwind-xamarin.csproj new file mode 100644 index 00000000000..b7aba4a3cfb --- /dev/null +++ b/src/native/libunwind/libunwind-xamarin.csproj @@ -0,0 +1,15 @@ + + + Exe + netstandard2.0 + False + + + + + + $(MicrosoftAndroidSdkOutDir)lib + + + + diff --git a/src/native/libunwind/libunwind-xamarin.targets b/src/native/libunwind/libunwind-xamarin.targets new file mode 100644 index 00000000000..3b989aec4aa --- /dev/null +++ b/src/native/libunwind/libunwind-xamarin.targets @@ -0,0 +1,54 @@ + + + + + + + <_LibUnwindBaseLibName>unwind_xamarin + <_LibUnwindLibName>lib$(_LibUnwindBaseLibName).a + <_LibUnwindHeadersOutputDir>$(LibUnwindGeneratedHeadersFullPath) + + + + + + + + <_ConfigureLibUnwindCommands + Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + $(_CmakeAndroidFlags) -DANDROID_NATIVE_API_LEVEL=%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_PLATFORM=android-%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_ABI=%(AndroidSupportedTargetJitAbi.Identity) -DANDROID_RID=%(AndroidSupportedTargetJitAbi.AndroidRID) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_BUILD_TYPE=$(Configuration) -DLIBUNWIND_SOURCE_DIR="$(LibUnwindSourceFullPath)" -DLIBUNWIND_LIBRARY_NAME="$(_LibUnwindBaseLibName)" -DLIBUNWIND_OUTPUT_DIR="@(AndroidSupportedTargetJitAbi->'$(OutputPath)/%(AndroidRID)')" -DLIBUNWIND_HEADERS_OUTPUT_DIR="$(_LibUnwindHeadersOutputDir)" $(MSBuildThisFileDirectory) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.Identity)-$(Configuration) + + + + + + + + + + + <_BuildLibUnwindCommands + Include="@(AndroidSupportedTargetJitAbi)"> + $(NinjaPath) + -v + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.Identity)-$(Configuration) + + + + + + + + + + + diff --git a/src/native/lz4/CMakeLists.txt b/src/native/lz4/CMakeLists.txt new file mode 100644 index 00000000000..fccd31776c8 --- /dev/null +++ b/src/native/lz4/CMakeLists.txt @@ -0,0 +1,39 @@ +set(LIB_NAME xa-lz4) +set(LIB_ALIAS xa::lz4) + +set(LZ4_SRC_DIR "${EXTERNAL_DIR}/lz4/lib") +set(LZ4_INCLUDE_DIR ${LZ4_SRC_DIR}) + +set(LZ4_SOURCES + ${LZ4_SRC_DIR}/lz4.c +) + +add_library( + ${LIB_NAME} + STATIC + ${LZ4_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +target_compile_definitions( + ${LIB_NAME} + PRIVATE + # Ugly, but this is the only way to change LZ4 symbols visibility without modifying lz4.h + "LZ4LIB_VISIBILITY=__attribute__ ((visibility (\"hidden\")))" + XXH_NAMESPACE=LZ4_ +) + +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" +) + +set_target_properties( + ${LIB_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/monodroid/jni/.gitignore b/src/native/monodroid/.gitignore similarity index 68% rename from src/monodroid/jni/.gitignore rename to src/native/monodroid/.gitignore index 7454689c137..b794e58ba97 100644 --- a/src/monodroid/jni/.gitignore +++ b/src/native/monodroid/.gitignore @@ -1,6 +1,5 @@ -Application.mk -config.include -machine.config.include +libs +sources.projitems pinvoke-tables.include.generated pinvoke-tables.include.diff generate-pinvoke-tables diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt new file mode 100644 index 00000000000..a8d067baed5 --- /dev/null +++ b/src/native/monodroid/CMakeLists.txt @@ -0,0 +1,181 @@ +option(ENABLE_TIMING "Build with timing support" OFF) + +# Needed modules + +include(CheckIncludeFile) +include(CheckCXXSymbolExists) + +# Paths + +set(BIONIC_SOURCES_DIR "${REPO_ROOT_DIR}/src-ThirdParty/bionic") +set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") + +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}) +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 + +if(ENABLE_CLANG_UBSAN OR ENABLE_CLANG_ASAN) + set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -llog") + string(STRIP "${CMAKE_REQUIRED_FLAGS}" CMAKE_REQUIRED_FLAGS) +endif() + +check_include_file("linux/netlink.h" HAVE_LINUX_NETLINK_H) +check_include_file("linux/rtnetlink.h" HAVE_LINUX_RTNETLINK_H) +check_include_file("linux/if_arp.h" HAVE_LINUX_IF_ARP_H) + +if(ENABLE_CLANG_UBSAN OR ENABLE_CLANG_ASAN) + set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") +endif() + +# Sources +string(TOLOWER ${CMAKE_BUILD_TYPE} XAMARIN_MONO_ANDROID_SUFFIX) +set(XAMARIN_MONO_ANDROID_LIB "mono-android${CHECKED_BUILD_INFIX}.${XAMARIN_MONO_ANDROID_SUFFIX}") + +set(XAMARIN_MONODROID_SOURCES + debug-constants.cc + debug.cc + embedded-assemblies-zip.cc + embedded-assemblies.cc + globals.cc + jni-remapping.cc + mono-log-adapter.cc + monodroid-glue.cc + monodroid-networkinfo.cc + monodroid-tracing.cc + monovm-properties.cc + osbridge.cc + pinvoke-override-api.cc + runtime-util.cc + timing.cc + timezones.cc + timing-internal.cc + xamarin_getifaddrs.cc +) + +list(APPEND LOCAL_CLANG_CHECK_SOURCES + ${XAMARIN_MONODROID_SOURCES} +) + +if(NOT DEBUG_BUILD) + list(APPEND XAMARIN_MONODROID_SOURCES + xamarin-android-app-context.cc + ) + + list(APPEND LOCAL_CLANG_CHECK_SOURCES + xamarin-android-app-context.cc + ) +endif() +add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") + +if(NOT USES_LIBSTDCPP) + list(APPEND XAMARIN_MONODROID_SOURCES + ${BIONIC_SOURCES_DIR}/cxa_guard.cc + ) +endif() + +# Build +configure_file(host-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/host-config.h) + +add_library( + ${XAMARIN_MONO_ANDROID_LIB} + SHARED ${XAMARIN_MONODROID_SOURCES} +) + +target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + HAVE_CONFIG_H + HAVE_LZ4 + JI_DLL_EXPORT + JI_NO_VISIBILITY + MONO_DLL_EXPORT + NET + TSL_NO_EXCEPTIONS +) + +if(DONT_INLINE) + target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + NO_INLINE + ) +endif() + +if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + DEBUG + ) +endif() + +if (ENABLE_TIMING) + target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + MONODROID_TIMING + ) +endif() + +target_compile_options( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} +) + +target_include_directories( + ${XAMARIN_MONO_ANDROID_LIB} BEFORE + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/include + ${EXTERNAL_DIR} + ${ROBIN_MAP_DIR}/include +) + +target_include_directories( + ${XAMARIN_MONO_ANDROID_LIB} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} + ${NATIVE_TRACING_INCLUDE_DIRS} + ${LIBUNWIND_INCLUDE_DIRS} +) + +target_link_directories( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + ${NET_RUNTIME_DIR}/native +) + +target_link_options( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} +) + +target_link_libraries( + ${XAMARIN_MONO_ANDROID_LIB} + ${LINK_LIBS} + xa::xamarin-app + ${SHARED_LIB_NAME} + xa::runtime-base + xa::java-interop + xa::lz4 + -lmonosgen-2.0 + -llog +) + +xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) diff --git a/src/monodroid/jni/build-info.hh b/src/native/monodroid/build-info.hh similarity index 100% rename from src/monodroid/jni/build-info.hh rename to src/native/monodroid/build-info.hh diff --git a/src/monodroid/jni/config.h b/src/native/monodroid/config.h similarity index 100% rename from src/monodroid/jni/config.h rename to src/native/monodroid/config.h diff --git a/src/native/monodroid/debug-constants.cc b/src/native/monodroid/debug-constants.cc new file mode 100644 index 00000000000..cf30e8a3621 --- /dev/null +++ b/src/native/monodroid/debug-constants.cc @@ -0,0 +1,10 @@ +#include "debug.hh" +#include "shared-constants.hh" + +using namespace xamarin::android; +using namespace xamarin::android::internal; + +extern "C" const char *__get_debug_mono_log_property (void) +{ + return static_cast (SharedConstants::DEBUG_MONO_LOG_PROPERTY.data ()); +} diff --git a/src/monodroid/jni/debug.cc b/src/native/monodroid/debug.cc similarity index 88% rename from src/monodroid/jni/debug.cc rename to src/native/monodroid/debug.cc index 33f9c0aaa67..7397fece427 100644 --- a/src/monodroid/jni/debug.cc +++ b/src/native/monodroid/debug.cc @@ -69,29 +69,29 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (col != nullptr) { size_t name_len = static_cast(col - desc); - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, name_len, 1); + size_t alloc_size = Helpers::add_with_overflow_check (name_len, 1); mname_ptr = new char [alloc_size]; strncpy (mname_ptr, desc, name_len); mname_ptr [name_len] = 0; } else { - mname_ptr = utils.strdup_new (desc); + mname_ptr = Util::strdup_new (desc); } std::unique_ptr mname {mname_ptr}; unsigned int dlopen_flags = JAVA_INTEROP_LIB_LOAD_LOCALLY; - std::unique_ptr libname {utils.string_concat ("libmono-profiler-", mname.get (), ".so")}; + std::unique_ptr libname {Util::string_concat ("libmono-profiler-", mname.get (), ".so")}; bool found = false; - void *handle = androidSystem.load_dso_from_any_directories (libname.get (), dlopen_flags); + void *handle = AndroidSystem::load_dso_from_any_directories (libname.get (), dlopen_flags); found = load_profiler_from_handle (handle, desc, mname.get ()); if (!found && libmono_path != nullptr) { - std::unique_ptr full_path {utils.path_combine (libmono_path, libname.get ())}; - handle = androidSystem.load_dso (full_path.get (), dlopen_flags, FALSE); + std::unique_ptr full_path {Util::path_combine (libmono_path, libname.get ())}; + handle = AndroidSystem::load_dso (full_path.get (), dlopen_flags, FALSE); found = load_profiler_from_handle (handle, desc, mname.get ()); } if (found && logfile != nullptr) - utils.set_world_accessable (logfile); + Util::set_world_accessable (logfile); if (!found) log_warn (LOG_DEFAULT, @@ -123,7 +123,7 @@ Debug::load_profiler_from_handle (void *dso_handle, const char *desc, const char if (!dso_handle) return false; - std::unique_ptr symbol {utils.string_concat (INITIALIZER_NAME.data (), "_", name)}; + std::unique_ptr symbol {Util::string_concat (INITIALIZER_NAME.data (), "_", name)}; bool result = load_profiler (dso_handle, desc, symbol.get ()); if (result) @@ -133,29 +133,6 @@ Debug::load_profiler_from_handle (void *dso_handle, const char *desc, const char } #if defined (DEBUG) -void -Debug::set_debugger_log_level (const char *level) -{ - if (level == nullptr || *level == '\0') { - got_debugger_log_level = false; - return; - } - - unsigned long v = strtoul (level, nullptr, 0); - if (v == std::numeric_limits::max () && errno == ERANGE) { - log_error (LOG_DEFAULT, "Invalid debugger log level value '%s', expecting a positive integer or zero", level); - return; - } - - if (v > std::numeric_limits::max ()) { - log_warn (LOG_DEFAULT, "Debugger log level value is higher than the maximum of %u, resetting to the maximum value.", std::numeric_limits::max ()); - v = std::numeric_limits::max (); - } - - got_debugger_log_level = true; - debugger_log_level = static_cast(v); -} - inline void Debug::parse_options (char *options, ConnOptions *opts) { @@ -163,7 +140,7 @@ Debug::parse_options (char *options, ConnOptions *opts) log_info (LOG_DEFAULT, "Connection options: '%s'", options); - args = utils.monodroid_strsplit (options, ",", 0); + args = Util::monodroid_strsplit (options, ",", 0); for (ptr = args; ptr && *ptr; ptr++) { const char *arg = *ptr; @@ -236,7 +213,7 @@ Debug::start_debugging_and_profiling () } char *connect_args = nullptr; - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_CONNECT_PROPERTY, &connect_args) > 0) { + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_CONNECT_PROPERTY, &connect_args) > 0) { DebuggerConnectionStatus res = start_connection (connect_args); if (res == DebuggerConnectionStatus::Error) { log_fatal (LOG_DEBUGGER, "Could not start a connection to the debugger with connection args '%s'.", connect_args); @@ -273,7 +250,7 @@ Debug::process_connection (int fd) char command [257]; uint8_t cmd_len; - ssize_t rv = utils.recv_uninterrupted (fd, &cmd_len, sizeof(cmd_len)); + ssize_t rv = Util::recv_uninterrupted (fd, &cmd_len, sizeof(cmd_len)); if (rv == 0) { log_info (LOG_DEFAULT, "EOF on socket.\n"); return false; @@ -283,7 +260,7 @@ Debug::process_connection (int fd) return false; } - rv = utils.recv_uninterrupted (fd, command, cmd_len); + rv = Util::recv_uninterrupted (fd, command, cmd_len); if (rv <= 0) { log_info (LOG_DEFAULT, "Error while receiving command from XS (%s)\n", strerror (errno)); return false; @@ -310,7 +287,7 @@ Debug::handle_server_connection (void) int flags = 1; int rv = setsockopt (listen_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); - if (rv == -1 && utils.should_log (LOG_DEFAULT)) { + if (rv == -1 && Util::should_log (LOG_DEFAULT)) { log_info_nocheck (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket (%s)", strerror (errno)); // not a fatal failure } @@ -457,7 +434,7 @@ Debug::process_cmd (int fd, char *cmd) constexpr std::string_view PING_CMD { "ping" }; constexpr std::string_view PONG_REPLY { "pong" }; if (strcmp (cmd, PING_CMD.data ()) == 0) { - if (!utils.send_uninterrupted (fd, const_cast (reinterpret_cast (PONG_REPLY.data ())), 5)) + if (!Util::send_uninterrupted (fd, const_cast (reinterpret_cast (PONG_REPLY.data ())), 5)) log_error (LOG_DEFAULT, "Got keepalive request from XS, but could not send response back (%s)\n", strerror (errno)); return false; } @@ -502,7 +479,7 @@ Debug::process_cmd (int fd, char *cmd) } else if (strncmp (prof, PROFILER_LOG.data (), PROFILER_LOG.length ()) == 0) { use_fd = true; profiler_fd = fd; - profiler_description = utils.monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); + profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { log_error (LOG_DEFAULT, "Unknown profiler: '%s'", prof); } @@ -535,7 +512,7 @@ Debug::start_debugging (void) embeddedAssemblies.set_register_debug_symbols (true); - char *debug_arg = utils.monodroid_strdup_printf ("--debugger-agent=transport=socket-fd,address=%d,embedding=1", sdb_fd); + char *debug_arg = Util::monodroid_strdup_printf ("--debugger-agent=transport=socket-fd,address=%d,embedding=1", sdb_fd); std::array debug_options = { debug_arg, nullptr @@ -571,7 +548,7 @@ Debug::start_profiling () return; log_info (LOG_DEFAULT, "Loading profiler: '%s'", profiler_description); - monodroid_profiler_load (androidSystem.get_runtime_libdir (), profiler_description, nullptr); + monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), profiler_description, nullptr); } static const char *soft_breakpoint_kernel_list[] = { @@ -597,18 +574,18 @@ Debug::enable_soft_breakpoints (void) char *value; /* Soft breakpoints are enabled by default */ - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_SOFT_BREAKPOINTS, &value) <= 0) { - log_info (LOG_DEBUGGER, "soft breakpoints enabled by default (%s property not defined)", Debug::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS, &value) <= 0) { + log_info (LOG_DEBUGGER, "soft breakpoints enabled by default (%s property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); return 1; } bool ret; if (strcmp ("0", value) == 0) { ret = false; - log_info (LOG_DEBUGGER, "soft breakpoints disabled (%s property set to %s)", Debug::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); + log_info (LOG_DEBUGGER, "soft breakpoints disabled (%s property set to %s)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); } else { ret = true; - log_info (LOG_DEBUGGER, "soft breakpoints enabled (%s property set to %s)", Debug::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); + log_info (LOG_DEBUGGER, "soft breakpoints enabled (%s property set to %s)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); } delete[] value; return ret; diff --git a/src/monodroid/jni/debug.hh b/src/native/monodroid/debug.hh similarity index 54% rename from src/monodroid/jni/debug.hh rename to src/native/monodroid/debug.hh index 9eafaa05624..e7f992d6aa2 100644 --- a/src/monodroid/jni/debug.hh +++ b/src/native/monodroid/debug.hh @@ -29,22 +29,6 @@ namespace xamarin::android private: static inline constexpr std::string_view INITIALIZER_NAME { "mono_profiler_init" }; - public: - /* Android property containing connection information, set by XS */ - static inline constexpr std::string_view DEBUG_MONO_CONNECT_PROPERTY { "debug.mono.connect" }; - static inline constexpr std::string_view DEBUG_MONO_DEBUG_PROPERTY { "debug.mono.debug" }; - static inline constexpr std::string_view DEBUG_MONO_ENV_PROPERTY { "debug.mono.env" }; - static inline constexpr std::string_view DEBUG_MONO_EXTRA_PROPERTY { "debug.mono.extra" }; - static inline constexpr std::string_view DEBUG_MONO_GC_PROPERTY { "debug.mono.gc" }; - static inline constexpr std::string_view DEBUG_MONO_GDB_PROPERTY { "debug.mono.gdb" }; - static inline constexpr std::string_view DEBUG_MONO_LOG_PROPERTY { "debug.mono.log" }; - static inline constexpr std::string_view DEBUG_MONO_MAX_GREFC { "debug.mono.max_grefc" }; - static inline constexpr std::string_view DEBUG_MONO_PROFILE_PROPERTY { "debug.mono.profile" }; - static inline constexpr std::string_view DEBUG_MONO_RUNTIME_ARGS_PROPERTY { "debug.mono.runtime_args" }; - static inline constexpr std::string_view DEBUG_MONO_SOFT_BREAKPOINTS { "debug.mono.soft_breakpoints" }; - static inline constexpr std::string_view DEBUG_MONO_TRACE_PROPERTY { "debug.mono.trace" }; - static inline constexpr std::string_view DEBUG_MONO_WREF_PROPERTY { "debug.mono.wref" }; - public: explicit Debug () {} @@ -59,17 +43,6 @@ namespace xamarin::android public: bool enable_soft_breakpoints (); void start_debugging_and_profiling (); - void set_debugger_log_level (const char *level); - - bool have_debugger_log_level () const - { - return got_debugger_log_level; - } - - int get_debugger_log_level () const - { - return debugger_log_level; - } private: DebuggerConnectionStatus start_connection (char *options); @@ -95,8 +68,6 @@ namespace xamarin::android bool config_timedout; timeval wait_tv; timespec wait_ts; - bool got_debugger_log_level = false; - int debugger_log_level = 0; #endif // def DEBUG }; } diff --git a/src/monodroid/jni/designer-assemblies.cc b/src/native/monodroid/designer-assemblies.cc similarity index 100% rename from src/monodroid/jni/designer-assemblies.cc rename to src/native/monodroid/designer-assemblies.cc diff --git a/src/monodroid/jni/designer-assemblies.hh b/src/native/monodroid/designer-assemblies.hh similarity index 100% rename from src/monodroid/jni/designer-assemblies.hh rename to src/native/monodroid/designer-assemblies.hh diff --git a/src/monodroid/jni/embedded-assemblies-zip.cc b/src/native/monodroid/embedded-assemblies-zip.cc similarity index 96% rename from src/monodroid/jni/embedded-assemblies-zip.cc rename to src/native/monodroid/embedded-assemblies-zip.cc index 30b10faaa1d..3ab4f90955e 100644 --- a/src/monodroid/jni/embedded-assemblies-zip.cc +++ b/src/native/monodroid/embedded-assemblies-zip.cc @@ -8,6 +8,7 @@ #include "embedded-assemblies.hh" #include "globals.hh" +#include "strings.hh" #include "xamarin-app.hh" #include "xxhash.hh" @@ -51,7 +52,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector const& entry_name, ZipEntryLoadState const& state, [[maybe_unused]] monodroid_should_register should_register) noexcept { #if defined (DEBUG) - const char *last_slash = utils.find_last (entry_name, '/'); + const char *last_slash = Util::find_last (entry_name, '/'); bool entry_is_overridden = last_slash == nullptr ? false : !should_register (last_slash + 1); #else constexpr bool entry_is_overridden = false; #endif - if (register_debug_symbols && !entry_is_overridden && utils.ends_with (entry_name, SharedConstants::PDB_EXTENSION)) { + if (register_debug_symbols && !entry_is_overridden && Util::ends_with (entry_name, SharedConstants::PDB_EXTENSION)) { if (bundled_debug_data == nullptr) { bundled_debug_data = new std::vector (); bundled_debug_data->reserve (application_config.number_of_assemblies_in_apk); @@ -89,7 +90,7 @@ EmbeddedAssemblies::store_individual_assembly_data (dynamic_local_string int fd; bool close_fd; - if (!androidSystem.is_embedded_dso_mode_enabled ()) { + if (!AndroidSystem::is_embedded_dso_mode_enabled ()) { log_debug (LOG_ASSEMBLY, "Mapping assembly blob file from filesystem"); close_fd = true; @@ -232,7 +233,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& continue; } - if (!assembly_store_found && utils.ends_with (entry_name, assembly_store_file_path)) { + if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path)) { assembly_store_found = true; map_assembly_store (entry_name, state); continue; @@ -244,7 +245,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& // Since it's not an assembly store, it's a shared library most likely and it is long enough for us not to have // to check the length - if (utils.ends_with (entry_name, dso_suffix)) { + if (Util::ends_with (entry_name, dso_suffix)) { constexpr size_t apk_lib_prefix_len = apk_lib_prefix.size () - 1; const char *const name = entry_name.get () + apk_lib_prefix_len; @@ -315,15 +316,15 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt { entry.file_fd = state.file_fd; if constexpr (NeedsNameAlloc) { - entry.name = utils.strdup_new (entry_name.get () + state.prefix_len); - if (!androidSystem.is_embedded_dso_mode_enabled () && state.file_name != nullptr) { - entry.file_name = utils.strdup_new (state.file_name); + entry.name = Util::strdup_new (entry_name.get () + state.prefix_len); + if (!AndroidSystem::is_embedded_dso_mode_enabled () && state.file_name != nullptr) { + entry.file_name = Util::strdup_new (state.file_name); } } else { // entry.name is preallocated at build time here and is max_name_size + 1 bytes long, filled with 0s, thus we // don't need to append the terminating NUL even for strings of `max_name_size` characters strncpy (entry.name, entry_name.get () + state.prefix_len, state.max_assembly_name_size); - if (!androidSystem.is_embedded_dso_mode_enabled () && state.file_name != nullptr) { + if (!AndroidSystem::is_embedded_dso_mode_enabled () && state.file_name != nullptr) { strncpy (entry.file_name, state.file_name, state.max_assembly_file_name_size); } } diff --git a/src/monodroid/jni/embedded-assemblies.cc b/src/native/monodroid/embedded-assemblies.cc similarity index 98% rename from src/monodroid/jni/embedded-assemblies.cc rename to src/native/monodroid/embedded-assemblies.cc index f9119817818..07eddf61114 100644 --- a/src/monodroid/jni/embedded-assemblies.cc +++ b/src/native/monodroid/embedded-assemblies.cc @@ -68,7 +68,7 @@ void EmbeddedAssemblies::set_assemblies_prefix (const char *prefix) { if (assemblies_prefix_override != nullptr) delete[] assemblies_prefix_override; - assemblies_prefix_override = prefix != nullptr ? utils.strdup_new (prefix) : nullptr; + assemblies_prefix_override = prefix != nullptr ? Util::strdup_new (prefix) : nullptr; } force_inline void @@ -159,7 +159,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc { int fd; bool close_fd; - if (!androidSystem.is_embedded_dso_mode_enabled ()) { + if (!AndroidSystem::is_embedded_dso_mode_enabled ()) { log_debug (LOG_ASSEMBLY, "Mapping a runtime file from a filesystem"); close_fd = true; @@ -200,7 +200,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc } if constexpr (LogMapping) { - if (utils.should_log (LOG_ASSEMBLY) && map_info.area != nullptr) [[unlikely]] { + if (Util::should_log (LOG_ASSEMBLY) && map_info.area != nullptr) [[unlikely]] { const char *p = (const char*) file.data; std::array header; @@ -300,7 +300,7 @@ template force_inline MonoAssembly* EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { - if (!utils.ends_with (name, SharedConstants::DLL_EXTENSION)) { + if (!Util::ends_with (name, SharedConstants::DLL_EXTENSION)) { name.append (SharedConstants::DLL_EXTENSION); } @@ -598,7 +598,7 @@ EmbeddedAssemblies::typemap_java_to_managed ([[maybe_unused]] hash_t hash, const return nullptr; } - MonoReflectionType *ret = mono_type_get_object (utils.get_current_domain (), type); + MonoReflectionType *ret = mono_type_get_object (Util::get_current_domain (), type); if (ret == nullptr) [[unlikely]] { log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '%s'", managed_type_name); return nullptr; @@ -865,7 +865,7 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons md_mmap_info file_info; md_mmap_info mmap_info; - size_t pageSize = static_cast(utils.monodroid_getpagesize ()); + size_t pageSize = static_cast(Util::monodroid_getpagesize ()); size_t offsetFromPage = offset % pageSize; size_t offsetPage = offset - offsetFromPage; size_t offsetSize = size + offsetFromPage; @@ -1015,7 +1015,7 @@ EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const bool EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char *dir_path, const char *file_path, int file_fd, TypeMap &module) { - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, header.assembly_name_length, 1); + size_t alloc_size = Helpers::add_with_overflow_check (header.assembly_name_length, 1); module.assembly_name = new char[alloc_size]; ssize_t nread = do_read (file_fd, module.assembly_name, header.assembly_name_length); @@ -1036,8 +1036,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * // [name][index] size_t java_entry_size = header.java_name_width + sizeof(uint32_t); size_t managed_entry_size = header.managed_name_width + sizeof(uint32_t); - size_t data_size = ADD_WITH_OVERFLOW_CHECK ( - size_t, + size_t data_size = Helpers::add_with_overflow_check ( header.entry_count * java_entry_size, header.entry_count * managed_entry_size ); @@ -1128,7 +1127,7 @@ EmbeddedAssemblies::try_load_typemaps_from_directory (const char *path) return; } - std::unique_ptr dir_path {utils.path_combine (path, "typemaps")}; + std::unique_ptr dir_path {Util::path_combine (path, "typemaps")}; DIR *dir; if ((dir = ::opendir (dir_path.get ())) == nullptr) { log_warn (LOG_ASSEMBLY, "typemap: could not open directory: `%s`", dir_path.get ()); @@ -1211,8 +1210,8 @@ EmbeddedAssemblies::maybe_register_assembly_from_filesystem ( return false; } } else { - if (utils.ends_with (dir_entry->d_name, SharedConstants::DLL_EXTENSION) || - utils.ends_with (dir_entry->d_name, SharedConstants::PDB_EXTENSION)) { + if (Util::ends_with (dir_entry->d_name, SharedConstants::DLL_EXTENSION) || + Util::ends_with (dir_entry->d_name, SharedConstants::PDB_EXTENSION)) { assembly_count++; copy_dentry_and_update_state (entry_name, state, dir_entry); } else { @@ -1359,7 +1358,7 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r log_debug (LOG_ASSEMBLY, "Registering assemblies from the filesystem"); constexpr bool LookForMangledNames = true; size_t assembly_count = register_from_filesystem ( - androidSystem.app_lib_directories[0], + AndroidSystem::app_lib_directories[0], LookForMangledNames, should_register ); @@ -1368,7 +1367,7 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r constexpr bool DoNotLookForMangledNames = false; assembly_count += register_from_filesystem ( - androidSystem.get_primary_override_dir (), + AndroidSystem::get_primary_override_dir (), DoNotLookForMangledNames, should_register ); diff --git a/src/monodroid/jni/embedded-assemblies.hh b/src/native/monodroid/embedded-assemblies.hh similarity index 100% rename from src/monodroid/jni/embedded-assemblies.hh rename to src/native/monodroid/embedded-assemblies.hh diff --git a/src/monodroid/jni/generate-pinvoke-tables.cc b/src/native/monodroid/generate-pinvoke-tables.cc similarity index 99% rename from src/monodroid/jni/generate-pinvoke-tables.cc rename to src/native/monodroid/generate-pinvoke-tables.cc index bcc9bce2acf..0c132d5461b 100644 --- a/src/monodroid/jni/generate-pinvoke-tables.cc +++ b/src/native/monodroid/generate-pinvoke-tables.cc @@ -61,12 +61,12 @@ const std::vector internal_pinvoke_names = { "_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_store_package_name", "monodroid_strdup_printf", "monodroid_strfreev", "monodroid_strsplit", diff --git a/src/monodroid/jni/globals.cc b/src/native/monodroid/globals.cc similarity index 100% rename from src/monodroid/jni/globals.cc rename to src/native/monodroid/globals.cc diff --git a/src/monodroid/jni/globals.hh b/src/native/monodroid/globals.hh similarity index 83% rename from src/monodroid/jni/globals.hh rename to src/native/monodroid/globals.hh index 67d482acea1..7717ec2ec79 100644 --- a/src/monodroid/jni/globals.hh +++ b/src/native/monodroid/globals.hh @@ -10,8 +10,6 @@ #include "monodroid-glue-internal.hh" extern xamarin::android::Debug debug; -extern xamarin::android::Util utils; -extern xamarin::android::internal::AndroidSystem androidSystem; extern xamarin::android::internal::OSBridge osBridge; extern xamarin::android::internal::EmbeddedAssemblies embeddedAssemblies; extern xamarin::android::internal::MonodroidRuntime monodroidRuntime; diff --git a/src/monodroid/jni/host-config.h.in b/src/native/monodroid/host-config.h.in similarity index 100% rename from src/monodroid/jni/host-config.h.in rename to src/native/monodroid/host-config.h.in diff --git a/src/monodroid/jni/internal-pinvoke-api.cc b/src/native/monodroid/internal-pinvoke-api.cc similarity index 100% rename from src/monodroid/jni/internal-pinvoke-api.cc rename to src/native/monodroid/internal-pinvoke-api.cc diff --git a/src/monodroid/jni/jni-remapping.cc b/src/native/monodroid/jni-remapping.cc similarity index 100% rename from src/monodroid/jni/jni-remapping.cc rename to src/native/monodroid/jni-remapping.cc diff --git a/src/monodroid/jni/jni-remapping.hh b/src/native/monodroid/jni-remapping.hh similarity index 100% rename from src/monodroid/jni/jni-remapping.hh rename to src/native/monodroid/jni-remapping.hh diff --git a/src/monodroid/jni/mono-image-loader.hh b/src/native/monodroid/mono-image-loader.hh similarity index 100% rename from src/monodroid/jni/mono-image-loader.hh rename to src/native/monodroid/mono-image-loader.hh diff --git a/src/monodroid/jni/mono-log-adapter.cc b/src/native/monodroid/mono-log-adapter.cc similarity index 100% rename from src/monodroid/jni/mono-log-adapter.cc rename to src/native/monodroid/mono-log-adapter.cc diff --git a/src/monodroid/jni/mono_android_Runtime.h b/src/native/monodroid/mono_android_Runtime.h similarity index 100% rename from src/monodroid/jni/mono_android_Runtime.h rename to src/native/monodroid/mono_android_Runtime.h diff --git a/src/monodroid/jni/monodroid-glue-designer.cc b/src/native/monodroid/monodroid-glue-designer.cc similarity index 100% rename from src/monodroid/jni/monodroid-glue-designer.cc rename to src/native/monodroid/monodroid-glue-designer.cc diff --git a/src/monodroid/jni/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh similarity index 93% rename from src/monodroid/jni/monodroid-glue-internal.hh rename to src/native/monodroid/monodroid-glue-internal.hh index abd3401671c..a8245495dd4 100644 --- a/src/monodroid/jni/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -64,6 +64,15 @@ namespace xamarin::android::internal } }; + // Values must be identical to those in src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs + enum class TraceKind : uint32_t + { + Java = 0x01, + Managed = 0x02, + Native = 0x04, + Signals = 0x08, + }; + class MonodroidRuntime { using pinvoke_api_map = tsl::robin_map< @@ -146,6 +155,9 @@ namespace xamarin::android::internal static constexpr std::string_view mono_component_diagnostics_tracing_name { "libmono-component-diagnostics_tracing.so" }; static constexpr hash_t mono_component_diagnostics_tracing_hash = xxhash::hash (mono_component_diagnostics_tracing_name); + static constexpr std::string_view xamarin_native_tracing_name { "libxamarin-native-tracing.so" }; + static constexpr hash_t xamarin_native_tracing_name_hash = xxhash::hash (xamarin_native_tracing_name); + public: static constexpr int XA_LOG_COUNTERS = MONO_COUNTER_JIT | MONO_COUNTER_METADATA | MONO_COUNTER_GC | MONO_COUNTER_GENERICS | MONO_COUNTER_INTERP; @@ -190,6 +202,7 @@ namespace xamarin::android::internal void propagate_uncaught_exception (JNIEnv *env, jobject javaThread, jthrowable javaException); char* get_java_class_name_for_TypeManager (jclass klass); + void log_traces (JNIEnv *env, TraceKind kind, const char *first_line) noexcept; private: static void mono_log_handler (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); @@ -209,6 +222,22 @@ namespace xamarin::android::internal static PinvokeEntry* find_pinvoke_address (hash_t hash, const PinvokeEntry *entries, size_t entry_count) noexcept; static void* handle_other_pinvoke_request (const char *library_name, hash_t library_name_hash, const char *entrypoint_name, hash_t entrypoint_name_hash) noexcept; static void* monodroid_pinvoke_override (const char *library_name, const char *entrypoint_name); + + template + static void load_symbol (void *handle, const char *name, TFunc*& fnptr) noexcept + { + char *err = nullptr; + void *symptr = monodroid_dlsym (handle, name, &err, nullptr); + + if (symptr == nullptr) { + log_warn (LOG_DEFAULT, "Failed to load symbol '%s' library with handle %p. %s", name, handle, err == nullptr ? "Unknown error" : err); + fnptr = nullptr; + return; + } + + fnptr = reinterpret_cast(symptr); + } + static void* monodroid_dlopen_ignore_component_or_load (hash_t hash, const char *name, int flags, char **err) noexcept; static void* monodroid_dlopen (const char *name, int flags, char **err) noexcept; static void* monodroid_dlopen (const char *name, int flags, char **err, void *user_data) noexcept; diff --git a/src/monodroid/jni/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc similarity index 91% rename from src/monodroid/jni/monodroid-glue.cc rename to src/native/monodroid/monodroid-glue.cc index 96cdb6f9473..029d3764153 100644 --- a/src/monodroid/jni/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -64,6 +64,7 @@ #include "startup-aware-lock.hh" #include "timing-internal.hh" #include "search.hh" +#include "runtime-util.hh" //#include "xamarin_getifaddrs.h" @@ -170,26 +171,26 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] } pname.append (name, name_len); - bool is_dll = utils.ends_with (name, SharedConstants::DLL_EXTENSION); + bool is_dll = Util::ends_with (name, SharedConstants::DLL_EXTENSION); size_t file_name_len = pname.length () + 1; if (!is_dll) file_name_len += SharedConstants::DLL_EXTENSION.length (); MonoAssembly *result = nullptr; for (const char *override_dir : AndroidSystem::override_dirs) { - if (override_dir == nullptr || !utils.directory_exists (override_dir)) { + if (override_dir == nullptr || !Util::directory_exists (override_dir)) { continue; } size_t override_dir_len = strlen (override_dir); static_local_string fullpath (override_dir_len + file_name_len); - utils.path_combine (fullpath, override_dir, override_dir_len, pname.get (), pname.length ()); + Util::path_combine (fullpath, override_dir, override_dir_len, pname.get (), pname.length ()); if (!is_dll) { fullpath.append (SharedConstants::DLL_EXTENSION); } log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: %s\n", fullpath.get ()); - if (utils.file_exists (fullpath.get ())) { + if (Util::file_exists (fullpath.get ())) { MonoImageOpenStatus status{}; result = mono_assembly_open_full (fullpath.get (), &status, 0); if (result == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { @@ -204,7 +205,7 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] } } - if (result != nullptr && utils.should_log (LOG_ASSEMBLY)) { + if (result != nullptr && Util::should_log (LOG_ASSEMBLY)) { log_info_nocheck (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: %p\n", result); } return result; @@ -227,8 +228,8 @@ MonodroidRuntime::should_register_file ([[maybe_unused]] const char *filename) size_t odir_len = strlen (odir); static_local_string p (odir_len + filename_len); - utils.path_combine (p, odir, odir_len, filename, filename_len); - bool exists = utils.file_exists (p.get ()); + Util::path_combine (p, odir, odir_len, filename, filename_len); + bool exists = Util::file_exists (p.get ()); if (exists) { return false; @@ -244,7 +245,7 @@ MonodroidRuntime::gather_bundled_assemblies (jstring_array_wrapper &runtimeApks, #if defined(DEBUG) if (application_config.instant_run_enabled) { for (const char *od : AndroidSystem::override_dirs) { - if (od == nullptr || !utils.directory_exists (od)) { + if (od == nullptr || !Util::directory_exists (od)) { continue; } @@ -257,7 +258,7 @@ MonodroidRuntime::gather_bundled_assemblies (jstring_array_wrapper &runtimeApks, } #endif - if (!androidSystem.is_embedded_dso_mode_enabled ()) { + if (!AndroidSystem::is_embedded_dso_mode_enabled ()) { *out_user_assemblies_count = embeddedAssemblies.register_from_filesystem (); return; } @@ -275,9 +276,9 @@ MonodroidRuntime::gather_bundled_assemblies (jstring_array_wrapper &runtimeApks, // 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 && utils.ends_with (apk_file.get_cstr (), SharedConstants::split_config_abi_apk_name)) { + if (!got_split_config_abi_apk && Util::ends_with (apk_file.get_cstr (), SharedConstants::split_config_abi_apk_name)) { got_split_config_abi_apk = scan_apk = true; - } else if (!application_config.have_assembly_store && !got_base_apk && utils.ends_with (apk_file.get_cstr (), base_apk_name)) { + } else if (!application_config.have_assembly_store && !got_base_apk && Util::ends_with (apk_file.get_cstr (), base_apk_name)) { got_base_apk = scan_apk = true; } @@ -378,7 +379,7 @@ MonodroidRuntime::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) { JNIEnv *env; - androidSystem.init_max_gref_count (); + AndroidSystem::init_max_gref_count (); vm->GetEnv ((void**)&env, JNI_VERSION_1_6); osBridge.initialize_on_onload (vm, env); @@ -391,7 +392,7 @@ MonodroidRuntime::parse_gdb_options () { dynamic_local_string val; - if (!(androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_GDB_PROPERTY, val) > 0)) + if (!(AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_GDB_PROPERTY, val) > 0)) return; constexpr std::string_view wait_param { "wait:" }; @@ -410,7 +411,7 @@ MonodroidRuntime::parse_gdb_options () time_t secs = time (nullptr); if (v + 10 < secs) { - log_warn (LOG_DEFAULT, "Found stale %s property with value '%s', not waiting.", Debug::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); + log_warn (LOG_DEFAULT, "Found stale %s property with value '%s', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); do_wait = false; } } @@ -456,7 +457,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_stringhost = host; options->sdb_port = static_cast(sdb_port); @@ -524,7 +525,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string jit_log_path {utils.path_combine (AndroidSystem::override_dirs [0], "methods.txt")}; - utils.create_directory (AndroidSystem::override_dirs [0], 0755); - jit_log = utils.monodroid_fopen (jit_log_path.get (), "a"); - utils.set_world_accessable (jit_log_path.get ()); + std::unique_ptr jit_log_path {Util::path_combine (AndroidSystem::override_dirs [0], "methods.txt")}; + Util::create_directory (AndroidSystem::override_dirs [0], 0755); + jit_log = Util::monodroid_fopen (jit_log_path.get (), "a"); + Util::set_world_accessable (jit_log_path.get ()); } profiler_handle = mono_profiler_create (nullptr); @@ -670,12 +671,12 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse dynamic_local_string prop_val; /* Additional runtime arguments passed to mono_jit_parse_options () */ - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; log_warn (LOG_DEBUGGER, "passing '%s' as extra arguments to the runtime.\n", prop_val.get ()); - char **args = utils.monodroid_strsplit (prop_val.get (), " ", 0); + char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; for (ptr = args; *ptr; ptr++) @@ -742,7 +743,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks } } - if (user_assemblies_count == 0 && androidSystem.count_override_assemblies () == 0 && !is_running_on_desktop) { + if (user_assemblies_count == 0 && AndroidSystem::count_override_assemblies () == 0 && !is_running_on_desktop) { #if defined (DEBUG) log_fatal (LOG_DEFAULT, "No assemblies found in '%s' or '%s'. Assuming this is part of Fast Deployment. Exiting...", AndroidSystem::override_dirs [0], @@ -764,7 +765,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks char *corlib_error_message = corlib_error_message_guard.get (); if (corlib_error_message == nullptr) { - if (!androidSystem.monodroid_get_system_property ("xamarin.studio.fakefaultycorliberrormessage", &corlib_error_message)) { + if (!AndroidSystem::monodroid_get_system_property ("xamarin.studio.fakefaultycorliberrormessage", &corlib_error_message)) { corlib_error_message = nullptr; } } @@ -794,7 +795,7 @@ MonodroidRuntime::LocalRefsAreIndirect (JNIEnv *env, jclass runtimeClass, int ve return 0; } - java_System = utils.get_class_from_runtime_field(env, runtimeClass, "java_lang_System", true); + java_System = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_System", true); java_System_identityHashCode = env->GetStaticMethodID (java_System, "identityHashCode", "(Ljava/lang/Object;)I"); return 1; @@ -874,17 +875,17 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec 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.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); log_info (LOG_GC, "GREF GC Threshold: %i", init.grefGcThreshold); - init.grefClass = utils.get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); + init.grefClass = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); init.Class_forName = env->GetStaticMethodID (init.grefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); MonoAssembly *mono_android_assembly; - mono_android_assembly = utils.monodroid_load_assembly (default_alc, SharedConstants::MONO_ANDROID_ASSEMBLY_NAME.data ()); + mono_android_assembly = Util::monodroid_load_assembly (default_alc, SharedConstants::MONO_ANDROID_ASSEMBLY_NAME.data ()); MonoImage *mono_android_assembly_image = mono_assembly_get_image (mono_android_assembly); uint32_t i = 0; @@ -911,7 +912,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless (method != nullptr, "INTERNAL ERROR: Unable to find the Android.Runtime.JNIEnvInit.Initialize method!"); MonoAssembly *ji_assm; - ji_assm = utils.monodroid_load_assembly (default_alc, SharedConstants::JAVA_INTEROP_ASSEMBLY_NAME.data ()); + ji_assm = Util::monodroid_load_assembly (default_alc, SharedConstants::JAVA_INTEROP_ASSEMBLY_NAME.data ()); MonoImage *ji_image = mono_assembly_get_image (ji_assm); for ( ; i < OSBridge::NUM_XA_GC_BRIDGE_TYPES + OSBridge::NUM_JI_GC_BRIDGE_TYPES; ++i) { @@ -941,7 +942,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec env->DeleteLocalRef (lrefLoaderClass); init.grefLoader = env->NewGlobalRef (loader); - init.grefIGCUserPeer = utils.get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true); + init.grefIGCUserPeer = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true); osBridge.initialize_on_runtime_init (env, runtimeClass); @@ -972,7 +973,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec MonoClass* MonodroidRuntime::get_android_runtime_class () { - MonoAssembly *assm = utils.monodroid_load_assembly (default_alc, SharedConstants::MONO_ANDROID_ASSEMBLY_NAME.data ()); + MonoAssembly *assm = Util::monodroid_load_assembly (default_alc, SharedConstants::MONO_ANDROID_ASSEMBLY_NAME.data ()); MonoImage *image = mono_assembly_get_image (assm); return mono_class_from_name (image, SharedConstants::ANDROID_RUNTIME_NS_NAME.data (), SharedConstants::JNIENV_CLASS_NAME.data ()); } @@ -995,8 +996,8 @@ MonodroidRuntime::propagate_uncaught_exception (JNIEnv *env, jobject javaThread, static void setup_gc_logging (void) { - gc_spew_enabled = androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_GC_PROPERTY, nullptr) > 0; - if (gc_spew_enabled) { + Logger::set_gc_spew_enabled (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_GC_PROPERTY, nullptr) > 0); + if (Logger::gc_spew_enabled ()) { log_categories |= LOG_GC; } } @@ -1032,7 +1033,7 @@ MonodroidRuntime::monodroid_dlopen_log_and_return (void *handle, char **err, con if (load_error == nullptr) { load_error = "Unknown error"; } - *err = utils.monodroid_strdup_printf ("Could not load library '%s'. %s", full_name, load_error); + *err = Util::monodroid_strdup_printf ("Could not load library '%s'. %s", full_name, load_error); } if (free_memory) { @@ -1077,12 +1078,12 @@ MonodroidRuntime::monodroid_dlopen_ignore_component_or_load ([[maybe_unused]] ha } unsigned int dl_flags = monodroidRuntime.convert_dl_flags (flags); - void * handle = androidSystem.load_dso_from_any_directories (name, dl_flags); + void * handle = AndroidSystem::load_dso_from_any_directories (name, dl_flags); if (handle != nullptr) { return monodroid_dlopen_log_and_return (handle, err, name, false /* name_needs_free */); } - handle = androidSystem.load_dso (name, dl_flags, false /* skip_existing_check */); + handle = AndroidSystem::load_dso (name, dl_flags, false /* skip_existing_check */); return monodroid_dlopen_log_and_return (handle, err, name, false /* name_needs_free */); } @@ -1108,7 +1109,7 @@ MonodroidRuntime::monodroid_dlopen (const char *name, int flags, char **err) noe StartupAwareLock lock (dso_handle_write_lock); #if defined (RELEASE) - if (androidSystem.is_embedded_dso_mode_enabled ()) { + if (AndroidSystem::is_embedded_dso_mode_enabled ()) { DSOApkEntry *apk_entry = dso_apk_entries; for (size_t i = 0; i < application_config.number_of_shared_libraries; i++) { if (apk_entry->name_hash != dso->real_name_hash) { @@ -1130,13 +1131,13 @@ MonodroidRuntime::monodroid_dlopen (const char *name, int flags, char **err) noe } #endif unsigned int dl_flags = monodroidRuntime.convert_dl_flags (flags); - dso->handle = androidSystem.load_dso_from_any_directories (dso->name, dl_flags); + dso->handle = AndroidSystem::load_dso_from_any_directories (dso->name, dl_flags); if (dso->handle != nullptr) { return monodroid_dlopen_log_and_return (dso->handle, err, dso->name, false /* name_needs_free */); } - dso->handle = androidSystem.load_dso_from_any_directories (name, dl_flags); + dso->handle = AndroidSystem::load_dso_from_any_directories (name, dl_flags); return monodroid_dlopen_log_and_return (dso->handle, err, name, false /* name_needs_free */); } @@ -1160,7 +1161,7 @@ MonodroidRuntime::monodroid_dlsym (void *handle, const char *name, char **err, [ s = java_interop_lib_symbol (handle, name, &e); if (!s && err) { - *err = utils.monodroid_strdup_printf ("Could not find symbol '%s': %s", name, e); + *err = Util::monodroid_strdup_printf ("Could not find symbol '%s': %s", name, e); } if (e) { java_interop_free (e); @@ -1173,7 +1174,7 @@ inline void MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstring_wrapper &value, bool createDirectory, mode_t mode) { if (createDirectory) { - int rv = utils.create_directory (value.get_cstr (), mode); + int rv = Util::create_directory (value.get_cstr (), mode); if (rv < 0 && errno != EEXIST) log_warn (LOG_DEFAULT, "Failed to create directory for environment variable %s. %s", name, strerror (errno)); } @@ -1184,9 +1185,9 @@ inline void MonodroidRuntime::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 ()); - utils.path_combine (dir, home.get_cstr (), home_len, relative_path.data (), relative_path.length ()); + Util::path_combine (dir, home.get_cstr (), home_len, relative_path.data (), relative_path.length ()); log_debug (LOG_DEFAULT, "Creating XDG directory: %s", dir.get ()); - int rv = utils.create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); + int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) log_warn (LOG_DEFAULT, "Failed to create XDG directory %s. %s", dir.get (), strerror (errno)); if (!environment_variable_name.empty ()) { @@ -1213,7 +1214,7 @@ void MonodroidRuntime::set_debug_env_vars (void) { dynamic_local_string value; - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_ENV_PROPERTY, value) == 0) + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_ENV_PROPERTY, value) == 0) return; auto log_envvar = [](const char *name, const char *v) { @@ -1253,7 +1254,7 @@ inline void MonodroidRuntime::set_trace_options (void) { dynamic_local_string value; - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_TRACE_PROPERTY, value) == 0) + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_TRACE_PROPERTY, value) == 0) return; mono_jit_set_trace_options (value.get ()); @@ -1267,7 +1268,7 @@ MonodroidRuntime::set_profile_options () dynamic_local_string value; { dynamic_local_string prop_value; - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_PROFILE_PROPERTY, prop_value) == 0) + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_PROFILE_PROPERTY, prop_value) == 0) return; value.assign (prop_value); @@ -1316,12 +1317,12 @@ MonodroidRuntime::set_profile_options () .append (OUTPUT_ARG) .append (output_path.get (), output_path.length ()); } - if (utils.create_directory (AndroidSystem::override_dirs[0], 0) < 0) { + if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { log_warn (LOG_DEFAULT, "Failed to create directory '%s'. %s", AndroidSystem::override_dirs[0], std::strerror (errno)); } log_warn (LOG_DEFAULT, "Initializing profiler with options: %s", value.get ()); - debug.monodroid_profiler_load (androidSystem.get_runtime_libdir (), value.get (), output_path.get ()); + debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } inline void @@ -1371,7 +1372,7 @@ MonodroidRuntime::load_assembly (MonoDomain *domain, jstring_wrapper &assembly) } MonoAssemblyName *aname = mono_assembly_name_new (assm_name); - MonoDomain *current = utils.get_current_domain (); + MonoDomain *current = Util::get_current_domain (); if (domain != current) { mono_domain_set (domain, FALSE); mono_assembly_load_full (aname, NULL, NULL, 0); @@ -1449,7 +1450,7 @@ MonodroidRuntime::create_and_initialize_domain (JNIEnv* env, jclass runtimeClass embeddedAssemblies.install_preload_hooks_for_alc (); log_debug (LOG_ASSEMBLY, "ALC hooks installed"); - bool preload = (androidSystem.is_assembly_preload_enabled () || (is_running_on_desktop && force_preload_assemblies)); + bool preload = (AndroidSystem::is_assembly_preload_enabled () || (is_running_on_desktop && force_preload_assemblies)); load_assemblies (default_alc, preload, assemblies); init_android_runtime (env, runtimeClass, loader); @@ -1568,13 +1569,13 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl char *mono_log_mask_raw = nullptr; char *mono_log_level_raw = nullptr; - init_logging_categories (mono_log_mask_raw, mono_log_level_raw); + Logger::init_logging_categories (mono_log_mask_raw, mono_log_level_raw); std::unique_ptr mono_log_mask (mono_log_mask_raw); std::unique_ptr mono_log_level (mono_log_level_raw); // If fast logging is disabled, log messages immediately - FastTiming::initialize ((log_timing_categories & LOG_TIMING_FAST_BARE) == 0); + FastTiming::initialize ((Logger::log_timing_categories() & LogTimingCategories::FastBare) != LogTimingCategories::FastBare); size_t total_time_index; if (FastTiming::enabled ()) [[unlikely]] { @@ -1604,28 +1605,26 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl } android_api_level = apiLevel; - androidSystem.detect_embedded_dso_mode (applicationDirs); - androidSystem.set_running_in_emulator (isEmulator); + AndroidSystem::detect_embedded_dso_mode (applicationDirs); + AndroidSystem::set_running_in_emulator (isEmulator); - java_TimeZone = utils.get_class_from_runtime_field (env, klass, "java_util_TimeZone", true); - - utils.monodroid_store_package_name (application_config.android_package_name); + java_TimeZone = RuntimeUtil::get_class_from_runtime_field (env, klass, "java_util_TimeZone", true); jstring_wrapper jstr (env, lang); set_environment_variable ("LANG", jstr); - androidSystem.setup_environment (); + AndroidSystem::setup_environment (); set_environment_variable_for_directory ("TMPDIR", applicationDirs[SharedConstants::APP_DIRS_CACHE_DIR_INDEX]); set_environment_variable_for_directory ("HOME", home); create_xdg_directories_and_environment (home); - androidSystem.set_primary_override_dir (home); + AndroidSystem::set_primary_override_dir (home); jstring_array_wrapper runtimeApks (env, runtimeApksJava); - androidSystem.setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); + AndroidSystem::setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); - init_reference_logging (androidSystem.get_primary_override_dir ()); - androidSystem.create_update_dir (androidSystem.get_primary_override_dir ()); + Logger::init_reference_logging (AndroidSystem::get_primary_override_dir ()); + AndroidSystem::create_update_dir (AndroidSystem::get_primary_override_dir ()); #if DEBUG setup_gc_logging (); @@ -1646,11 +1645,11 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; - androidSystem.set_runtime_libdir (strdup (jstr.get_cstr ())); - log_debug (LOG_DEFAULT, "Using runtime path: %s", androidSystem.get_runtime_libdir ()); + AndroidSystem::set_runtime_libdir (strdup (jstr.get_cstr ())); + log_debug (LOG_DEFAULT, "Using runtime path: %s", AndroidSystem::get_runtime_libdir ()); } - androidSystem.setup_process_args (runtimeApks); + AndroidSystem::setup_process_args (runtimeApks); mono_dl_fallback_register (monodroid_dlopen, monodroid_dlsym, nullptr, nullptr); set_profile_options (); @@ -1664,8 +1663,8 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl log_debug (LOG_DEFAULT, "Probing for Mono AOT mode\n"); MonoAotMode mode = MonoAotMode::MONO_AOT_MODE_NONE; - if (androidSystem.is_mono_aot_enabled ()) { - mode = androidSystem.get_mono_aot_mode (); + if (AndroidSystem::is_mono_aot_enabled ()) { + mode = AndroidSystem::get_mono_aot_mode (); if (mode != MonoAotMode::MONO_AOT_MODE_INTERP_ONLY) { log_debug (LOG_DEFAULT, "Enabling AOT mode in Mono"); } else { @@ -1676,7 +1675,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl log_debug (LOG_DEFAULT, "Probing if we should use LLVM\n"); - if (androidSystem.is_mono_llvm_enabled ()) { + if (AndroidSystem::is_mono_llvm_enabled ()) { char *args [1]; args[0] = const_cast ("--llvm"); log_debug (LOG_DEFAULT, "Enabling LLVM mode in Mono\n"); @@ -1685,7 +1684,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl } dynamic_local_string runtime_args; - androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_EXTRA_PROPERTY, runtime_args); + AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_EXTRA_PROPERTY, runtime_args); size_t mono_runtime_init_index; if (FastTiming::enabled ()) [[unlikely]] { @@ -1709,7 +1708,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl reinterpret_cast (monodroid_Mono_UnhandledException_internal)); } - if (utils.should_log (LOG_DEFAULT)) [[unlikely]] { + if (Util::should_log (LOG_DEFAULT)) [[unlikely]] { log_info_nocheck ( LOG_DEFAULT, ".NET for Android version: %s (%s; %s); built on %s; NDK version: %s; API level: %s; MonoVM version: %s", @@ -1738,6 +1737,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM *vm, void *reserved) { + Util::initialize (); return monodroidRuntime.Java_JNI_OnLoad (vm, reserved); } diff --git a/src/monodroid/jni/monodroid-glue.hh b/src/native/monodroid/monodroid-glue.hh similarity index 100% rename from src/monodroid/jni/monodroid-glue.hh rename to src/native/monodroid/monodroid-glue.hh diff --git a/src/monodroid/jni/monodroid-networkinfo.cc b/src/native/monodroid/monodroid-networkinfo.cc similarity index 95% rename from src/monodroid/jni/monodroid-networkinfo.cc rename to src/native/monodroid/monodroid-networkinfo.cc index a2aec751339..50267299def 100644 --- a/src/monodroid/jni/monodroid-networkinfo.cc +++ b/src/native/monodroid/monodroid-networkinfo.cc @@ -28,6 +28,7 @@ #include #include +#include "android-system.hh" #include "monodroid.h" #include "monodroid-glue.hh" @@ -35,6 +36,7 @@ #include "globals.hh" using namespace xamarin::android; +using namespace xamarin::android::internal; static pthread_once_t java_classes_once_control = PTHREAD_ONCE_INIT; static jclass NetworkInterface_class; @@ -153,7 +155,7 @@ _monodroid_get_dns_servers (void **dns_servers_array) char prop_name[] = "net.dnsX"; for (int i = 0; i < 8; i++) { prop_name [7] = (char)(i + 0x31); - len = static_cast(androidSystem.monodroid_get_system_property (prop_name, &dns)); + len = static_cast(AndroidSystem::monodroid_get_system_property (prop_name, &dns)); if (len == 0) { dns_servers [i] = nullptr; continue; @@ -165,7 +167,7 @@ _monodroid_get_dns_servers (void **dns_servers_array) if (count <= 0) return 0; - size_t alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, sizeof (char*), static_cast(count)); + size_t alloc_size = Helpers::multiply_with_overflow_check (sizeof (char*), static_cast(count)); char **ret = (char**)malloc (alloc_size); char **p = ret; for (int i = 0; i < 8; i++) { diff --git a/src/native/monodroid/monodroid-tracing.cc b/src/native/monodroid/monodroid-tracing.cc new file mode 100644 index 00000000000..e5d0771d49b --- /dev/null +++ b/src/native/monodroid/monodroid-tracing.cc @@ -0,0 +1,89 @@ +#include +#include + +#include "java-interop-logger.h" +#include "mono/utils/details/mono-dl-fallback-types.h" +#include "monodroid-glue-internal.hh" +#include "native-tracing.hh" +#include + +using namespace xamarin::android::internal; + +namespace { + decltype(xa_get_native_backtrace)* _xa_get_native_backtrace; + decltype(xa_get_managed_backtrace)* _xa_get_managed_backtrace; + decltype(xa_get_java_backtrace)* _xa_get_java_backtrace; + decltype(xa_get_interesting_signal_handlers)* _xa_get_interesting_signal_handlers; + bool tracing_init_done; + std::mutex tracing_init_lock {}; +} + +void +MonodroidRuntime::log_traces (JNIEnv *env, TraceKind kind, const char *first_line) noexcept +{ + if (!tracing_init_done) { + std::lock_guard lock (tracing_init_lock); + + char *err = nullptr; + void *handle = monodroid_dlopen (xamarin_native_tracing_name.data (), MONO_DL_EAGER, &err, nullptr); + if (handle == nullptr) { + log_warn (LOG_DEFAULT, "Failed to load native tracing library '%s'. %s", xamarin_native_tracing_name, err == nullptr ? "Unknown error" : err); + } else { + load_symbol (handle, "xa_get_native_backtrace", _xa_get_native_backtrace); + load_symbol (handle, "xa_get_managed_backtrace", _xa_get_managed_backtrace); + load_symbol (handle, "xa_get_java_backtrace", _xa_get_java_backtrace); + load_symbol (handle, "xa_get_interesting_signal_handlers", _xa_get_interesting_signal_handlers); + } + + tracing_init_done = true; + } + + std::string trace; + if (first_line != nullptr) { + trace.append (first_line); + trace.append ("\n"); + } + + bool need_newline = false; + auto add_trace = [&] (c_unique_ptr const& data, const char *banner) -> void { + if (need_newline) { + trace.append ("\n "); + } else { + trace.append (" "); + } + + trace.append (banner); + if (!data) { + trace.append (": unavailable"); + } else { + trace.append (":\n"); + trace.append (data.get ()); + trace.append ("\n"); + } + need_newline = true; + }; + + if ((kind & TraceKind::Native) == TraceKind::Native) { + c_unique_ptr native { _xa_get_native_backtrace != nullptr ? _xa_get_native_backtrace () : nullptr }; + add_trace (native, "Native stacktrace"); + } + + if ((kind & TraceKind::Java) == TraceKind::Java && env != nullptr) { + c_unique_ptr java { _xa_get_java_backtrace != nullptr ?_xa_get_java_backtrace (env) : nullptr }; + add_trace (java, "Java stacktrace"); + } + + if ((kind & TraceKind::Managed) == TraceKind::Managed) { + c_unique_ptr managed { _xa_get_managed_backtrace != nullptr ? _xa_get_managed_backtrace () : nullptr }; + add_trace (managed, "Managed stacktrace"); + } + + if ((kind & TraceKind::Signals) == TraceKind::Signals) { + c_unique_ptr signals { _xa_get_interesting_signal_handlers != nullptr ? _xa_get_interesting_signal_handlers () : nullptr }; + add_trace (signals, "Signal handlers"); + } + + // Use this call because it is slightly faster (doesn't need to parse the format) and it doesn't truncate longer + // strings (like the stack traces we've just produced), unlike __android_log_vprint used by our `log_*` functions + __android_log_write (ANDROID_LOG_INFO, SharedConstants::LOG_CATEGORY_NAME_MONODROID.data (), trace.c_str ()); +} diff --git a/src/monodroid/jni/monodroid.h b/src/native/monodroid/monodroid.h similarity index 100% rename from src/monodroid/jni/monodroid.h rename to src/native/monodroid/monodroid.h diff --git a/src/monodroid/jni/monodroid.x b/src/native/monodroid/monodroid.x similarity index 100% rename from src/monodroid/jni/monodroid.x rename to src/native/monodroid/monodroid.x diff --git a/src/monodroid/jni/monovm-properties.cc b/src/native/monodroid/monovm-properties.cc similarity index 100% rename from src/monodroid/jni/monovm-properties.cc rename to src/native/monodroid/monovm-properties.cc diff --git a/src/monodroid/jni/monovm-properties.hh b/src/native/monodroid/monovm-properties.hh similarity index 100% rename from src/monodroid/jni/monovm-properties.hh rename to src/native/monodroid/monovm-properties.hh diff --git a/src/monodroid/jni/osbridge.cc b/src/native/monodroid/osbridge.cc similarity index 97% rename from src/monodroid/jni/osbridge.cc rename to src/native/monodroid/osbridge.cc index dc8d50db6d3..e4c268ba63b 100644 --- a/src/monodroid/jni/osbridge.cc +++ b/src/native/monodroid/osbridge.cc @@ -17,12 +17,7 @@ #include "globals.hh" #include "osbridge.hh" - -// These two must stay here until JavaInterop is converted to C++ -FILE *gref_log; -FILE *lref_log; -bool gref_to_logcat; -bool lref_to_logcat; +#include "runtime-util.hh" using namespace xamarin::android; using namespace xamarin::android::internal; @@ -659,12 +654,12 @@ OSBridge::describe_target (OSBridge::AddReferenceTarget target) { if (target.is_mono_object) { MonoClass *klass = mono_object_get_class (target.obj); - return utils.monodroid_strdup_printf ("object of class %s.%s", + return Util::monodroid_strdup_printf ("object of class %s.%s", mono_class_get_namespace (klass), mono_class_get_name (klass)); } else - return utils.monodroid_strdup_printf ("", target.jobj); + return Util::monodroid_strdup_printf ("", target.jobj); } #endif @@ -691,7 +686,7 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri } #if DEBUG - if (gc_spew_enabled) { + if (Logger::gc_spew_enabled ()) { char *description = describe_target (target), *reffed_description = describe_target (reffed_target); @@ -928,7 +923,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } else { env->ExceptionClear (); #if DEBUG - if (gc_spew_enabled) { + if (Logger::gc_spew_enabled ()) { klass = mono_object_get_class (obj); log_error (LOG_GC, "Missing monodroidClearReferences method for object of class %s.%s", mono_class_get_namespace (klass), @@ -972,7 +967,7 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre return; #if DEBUG - if (gc_spew_enabled) { + if (Logger::gc_spew_enabled ()) { int i, j; log_info (LOG_GC, "cross references callback invoked with %d sccs and %d xrefs.", num_sccs, num_xrefs); @@ -988,7 +983,7 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre } } - if (utils.should_log (LOG_GC)) { + if (Util::should_log (LOG_GC)) { for (i = 0; i < num_xrefs; ++i) log_info_nocheck (LOG_GC, "xref [%d] %d -> %d", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); } @@ -1012,12 +1007,12 @@ OSBridge::platform_supports_weak_refs (void) char *value; int api_level = 0; - if (androidSystem.monodroid_get_system_property ("ro.build.version.sdk", &value) > 0) { + if (AndroidSystem::monodroid_get_system_property ("ro.build.version.sdk", &value) > 0) { api_level = atoi (value); free (value); } - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_WREF_PROPERTY, &value) > 0) { + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_WREF_PROPERTY, &value) > 0) { int use_weak_refs = 0; if (!strcmp ("jni", value)) use_weak_refs = 1; @@ -1072,7 +1067,7 @@ OSBridge::ensure_jnienv (void) JNIEnv *env; jvm->GetEnv ((void**)&env, JNI_VERSION_1_6); if (env == nullptr) { - mono_thread_attach (utils.get_current_domain (/* attach_thread_if_needed */ false)); + mono_thread_attach (Util::get_current_domain (/* attach_thread_if_needed */ false)); jvm->GetEnv ((void**)&env, JNI_VERSION_1_6); } return env; @@ -1107,7 +1102,7 @@ void OSBridge::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) { abort_if_invalid_pointer_argument (env); - GCUserPeer_class = utils.get_class_from_runtime_field(env, runtimeClass, "mono_android_GCUserPeer", true); + GCUserPeer_class = RuntimeUtil::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!"); } @@ -1121,7 +1116,7 @@ OSBridge::add_monodroid_domain (MonoDomain *domain) * use GC API to allocate memory and thus can't be called from within the GC callback as it causes a deadlock * (the routine allocating the memory waits for the GC round to complete first) */ - MonoClass *runtime = utils.monodroid_get_class_from_name ( + MonoClass *runtime = Util::monodroid_get_class_from_name ( domain, SharedConstants::MONO_ANDROID_RUNTIME_ASSEMBLY_NAME.data (), SharedConstants::ANDROID_RUNTIME_NS_NAME.data (), diff --git a/src/monodroid/jni/osbridge.hh b/src/native/monodroid/osbridge.hh similarity index 100% rename from src/monodroid/jni/osbridge.hh rename to src/native/monodroid/osbridge.hh diff --git a/src/monodroid/jni/pinvoke-override-api.cc b/src/native/monodroid/pinvoke-override-api.cc similarity index 95% rename from src/monodroid/jni/pinvoke-override-api.cc rename to src/native/monodroid/pinvoke-override-api.cc index 94232f60045..c020027eb8a 100644 --- a/src/monodroid/jni/pinvoke-override-api.cc +++ b/src/native/monodroid/pinvoke-override-api.cc @@ -39,7 +39,7 @@ monodroid_get_log_categories () static int monodroid_get_system_property (const char *name, char **value) { - return androidSystem.monodroid_get_system_property (name, value); + return AndroidSystem::monodroid_get_system_property (name, value); } static int @@ -92,7 +92,7 @@ monodroid_free (void *ptr) static int _monodroid_max_gref_get () { - return static_cast(androidSystem.get_max_gref_count ()); + return static_cast(AndroidSystem::get_max_gref_count ()); } static int @@ -240,13 +240,13 @@ monodroid_timing_stop (managed_timing_sequence *sequence, const char *message) static char** monodroid_strsplit (const char *str, const char *delimiter, size_t max_tokens) { - return utils.monodroid_strsplit (str, delimiter, max_tokens); + return Util::monodroid_strsplit (str, delimiter, max_tokens); } static void monodroid_strfreev (char **str_array) { - utils.monodroid_strfreev (str_array); + Util::monodroid_strfreev (str_array); } static char* @@ -255,7 +255,7 @@ monodroid_strdup_printf (const char *format, ...) va_list args; va_start (args, format); - char *ret = utils.monodroid_strdup_vprintf (format, args); + char *ret = Util::monodroid_strdup_vprintf (format, args); va_end (args); return ret; @@ -267,22 +267,16 @@ monodroid_TypeManager_get_java_class_name (jclass klass) return monodroidRuntime.get_java_class_name_for_TypeManager (klass); } -static void -monodroid_store_package_name (const char *name) -{ - utils.monodroid_store_package_name (name); -} - static int monodroid_get_namespaced_system_property (const char *name, char **value) { - return static_cast(androidSystem.monodroid_get_system_property (name, value)); + return static_cast(AndroidSystem::monodroid_get_system_property (name, value)); } static FILE* monodroid_fopen (const char* filename, const char* mode) { - return utils.monodroid_fopen (filename, mode); + return Util::monodroid_fopen (filename, mode); } static int @@ -290,7 +284,7 @@ send_uninterrupted (int fd, void *buf, int len) { if (len < 0) len = 0; - return utils.send_uninterrupted (fd, buf, static_cast(len)); + return Util::send_uninterrupted (fd, buf, static_cast(len)); } static int @@ -298,25 +292,25 @@ recv_uninterrupted (int fd, void *buf, int len) { if (len < 0) len = 0; - return static_cast(utils.recv_uninterrupted (fd, buf, static_cast(len))); + return static_cast(Util::recv_uninterrupted (fd, buf, static_cast(len))); } static void set_world_accessable (const char *path) { - utils.set_world_accessable (path); + Util::set_world_accessable (path); } static void create_public_directory (const char *dir) { - utils.create_public_directory (dir); + Util::create_public_directory (dir); } static char* path_combine (const char *path1, const char *path2) { - return utils.path_combine (path1, path2); + return Util::path_combine (path1, path2); } static void* @@ -363,6 +357,15 @@ _monodroid_lookup_replacement_method_info (const char *jniSourceType, const char return JniRemapping::lookup_replacement_method_info (jniSourceType, jniMethodName, jniMethodSignature); } +static void +monodroid_log_traces (uint32_t kind, const char *first_line) +{ + JNIEnv *env = osBridge.ensure_jnienv (); + auto tk = static_cast(kind); + + monodroidRuntime.log_traces (env, tk, first_line); +} + #include "pinvoke-tables.include" MonodroidRuntime::pinvoke_library_map MonodroidRuntime::other_pinvoke_map (MonodroidRuntime::LIBRARY_MAP_INITIAL_BUCKET_COUNT); diff --git a/src/monodroid/jni/pinvoke-tables.include b/src/native/monodroid/pinvoke-tables.include similarity index 99% rename from src/monodroid/jni/pinvoke-tables.include rename to src/native/monodroid/pinvoke-tables.include index 1f3c479095c..b422e0917a6 100644 --- a/src/monodroid/jni/pinvoke-tables.include +++ b/src/native/monodroid/pinvoke-tables.include @@ -13,11 +13,11 @@ static PinvokeEntry internal_pinvokes[] = { {0x452e23128e42f0a, "monodroid_get_log_categories", reinterpret_cast(&monodroid_get_log_categories)}, {0xa50ce5de13bf8b5, "_monodroid_timezone_get_default_id", reinterpret_cast(&_monodroid_timezone_get_default_id)}, {0x19055d65edfd668e, "_monodroid_get_network_interface_up_state", reinterpret_cast(&_monodroid_get_network_interface_up_state)}, - {0x2637a308c07d56b2, "monodroid_store_package_name", reinterpret_cast(&monodroid_store_package_name)}, {0x2b3b0ca1d14076da, "monodroid_get_dylib", reinterpret_cast(&monodroid_get_dylib)}, {0x2fbe68718cf2510d, "_monodroid_get_identity_hash_code", reinterpret_cast(&_monodroid_get_identity_hash_code)}, {0x3ade4348ac8ce0fa, "_monodroid_freeifaddrs", reinterpret_cast(&_monodroid_freeifaddrs)}, {0x3b2467e7eadd4a6a, "_monodroid_lref_log_new", reinterpret_cast(&_monodroid_lref_log_new)}, + {0x3b8097af56b5361f, "monodroid_log_traces", reinterpret_cast(&monodroid_log_traces)}, {0x3c5532ecdab53f89, "set_world_accessable", reinterpret_cast(&set_world_accessable)}, {0x423c8f539a2c56d2, "_monodroid_lookup_replacement_type", reinterpret_cast(&_monodroid_lookup_replacement_type)}, {0x4b1956138764939a, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, @@ -535,11 +535,11 @@ static PinvokeEntry internal_pinvokes[] = { {0xc439b5d7, "_monodroid_lookup_replacement_type", reinterpret_cast(&_monodroid_lookup_replacement_type)}, {0xc5146c54, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, {0xc58eafa5, "java_interop_free", reinterpret_cast(&java_interop_free)}, - {0xc6c99d41, "monodroid_store_package_name", reinterpret_cast(&monodroid_store_package_name)}, {0xd3b5d2c1, "_monodroid_freeifaddrs", reinterpret_cast(&_monodroid_freeifaddrs)}, {0xd78c749d, "monodroid_get_log_categories", reinterpret_cast(&monodroid_get_log_categories)}, {0xd91f3619, "create_public_directory", reinterpret_cast(&create_public_directory)}, {0xe215a17c, "_monodroid_weak_gref_delete", reinterpret_cast(&_monodroid_weak_gref_delete)}, + {0xe4c3ee19, "monodroid_log_traces", reinterpret_cast(&monodroid_log_traces)}, {0xe7e77ca5, "_monodroid_gref_log", reinterpret_cast(&_monodroid_gref_log)}, {0xea2184e3, "_monodroid_gc_wait_for_bridge_processing", reinterpret_cast(&_monodroid_gc_wait_for_bridge_processing)}, {0xf4079b4a, "monodroid_dylib_mono_new", reinterpret_cast(&monodroid_dylib_mono_new)}, diff --git a/src/native/monodroid/runtime-util.cc b/src/native/monodroid/runtime-util.cc new file mode 100644 index 00000000000..0fc8edc4482 --- /dev/null +++ b/src/native/monodroid/runtime-util.cc @@ -0,0 +1,20 @@ +#include "globals.hh" +#include "runtime-util.hh" + +using namespace xamarin::android::internal; + +jclass +RuntimeUtil::get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) +{ + 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/monodroid/runtime-util.hh b/src/native/monodroid/runtime-util.hh new file mode 100644 index 00000000000..8e6a39b4195 --- /dev/null +++ b/src/native/monodroid/runtime-util.hh @@ -0,0 +1,13 @@ +#if !defined(RUNTIME_UTIL_HH) +#define RUNTIME_UTIL_HH + +#include + +namespace xamarin::android::internal { + class RuntimeUtil + { + public: + static jclass get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref); + }; +} +#endif // ndef RUNTIME_UTIL_HH diff --git a/src/monodroid/jni/search.hh b/src/native/monodroid/search.hh similarity index 100% rename from src/monodroid/jni/search.hh rename to src/native/monodroid/search.hh diff --git a/src/monodroid/jni/startup-aware-lock.hh b/src/native/monodroid/startup-aware-lock.hh similarity index 100% rename from src/monodroid/jni/startup-aware-lock.hh rename to src/native/monodroid/startup-aware-lock.hh diff --git a/src/monodroid/jni/timezones.cc b/src/native/monodroid/timezones.cc similarity index 94% rename from src/monodroid/jni/timezones.cc rename to src/native/monodroid/timezones.cc index f5179350ed9..2680af72a2f 100644 --- a/src/monodroid/jni/timezones.cc +++ b/src/native/monodroid/timezones.cc @@ -33,7 +33,7 @@ init () if (AndroidEnvironment_NotifyTimeZoneChanged) return; - Mono_Android_dll = utils.monodroid_load_assembly (utils.get_current_domain (), SharedConstants::MONO_ANDROID_ASSEMBLY_NAME.data ()); + Mono_Android_dll = Util::monodroid_load_assembly (Util::get_current_domain (), SharedConstants::MONO_ANDROID_ASSEMBLY_NAME.data ()); Mono_Android_image = mono_assembly_get_image (Mono_Android_dll); AndroidEnvironment = mono_class_from_name (Mono_Android_image, SharedConstants::ANDROID_RUNTIME_NS_NAME.data (), SharedConstants::ANDROID_ENVIRONMENT_CLASS_NAME.data ()); AndroidEnvironment_NotifyTimeZoneChanged = mono_class_get_method_from_name (AndroidEnvironment, "NotifyTimeZoneChanged", 0); diff --git a/src/monodroid/jni/timing-internal.cc b/src/native/monodroid/timing-internal.cc similarity index 100% rename from src/monodroid/jni/timing-internal.cc rename to src/native/monodroid/timing-internal.cc diff --git a/src/monodroid/jni/timing-internal.hh b/src/native/monodroid/timing-internal.hh similarity index 97% rename from src/monodroid/jni/timing-internal.hh rename to src/native/monodroid/timing-internal.hh index 47417123f27..519b98cb28e 100644 --- a/src/monodroid/jni/timing-internal.hh +++ b/src/native/monodroid/timing-internal.hh @@ -6,6 +6,7 @@ #include #include +#include "cpp-util.hh" #include "logger.hh" #include "startup-aware-lock.hh" #include "strings.hh" @@ -100,13 +101,13 @@ namespace xamarin::android::internal force_inline static bool is_bare_mode () noexcept { return - (log_timing_categories & LOG_TIMING_BARE) == LOG_TIMING_BARE || - (log_timing_categories & LOG_TIMING_FAST_BARE) == LOG_TIMING_FAST_BARE; + (Logger::log_timing_categories() & LogTimingCategories::Bare) == LogTimingCategories::Bare || + (Logger::log_timing_categories() & LogTimingCategories::FastBare) == LogTimingCategories::FastBare; } force_inline static void initialize (bool log_immediately) noexcept { - if (!utils.should_log (LOG_TIMING)) [[likely]] { + if (!Util::should_log (LOG_TIMING)) [[likely]] { return; } @@ -172,7 +173,7 @@ namespace xamarin::android::internal return; } - events[event_index].more_info = utils.strdup_new (str.get (), str.length ()); + events[event_index].more_info = Util::strdup_new (str.get (), str.length ()); log (events[event_index], false /* skip_log_if_more_info_missing */); } @@ -182,7 +183,7 @@ namespace xamarin::android::internal return; } - events[event_index].more_info = utils.strdup_new (str, strlen (str)); + events[event_index].more_info = Util::strdup_new (str, strlen (str)); log (events[event_index], false /* skip_log_if_more_info_missing */); } diff --git a/src/native/monodroid/timing.cc b/src/native/monodroid/timing.cc new file mode 100644 index 00000000000..023b16271ec --- /dev/null +++ b/src/native/monodroid/timing.cc @@ -0,0 +1,14 @@ +#include "timing-internal.hh" + +using namespace xamarin::android; +using namespace xamarin::android::internal; + +void timing_point::mark () +{ + FastTiming::get_time (sec, ns); +} + +timing_diff::timing_diff (const timing_period &period) +{ + FastTiming::calculate_interval (period.start, period.end, *this); +} diff --git a/src/monodroid/jni/timing.hh b/src/native/monodroid/timing.hh similarity index 100% rename from src/monodroid/jni/timing.hh rename to src/native/monodroid/timing.hh diff --git a/src/monodroid/jni/win32/jni_md.h b/src/native/monodroid/win32/jni_md.h similarity index 100% rename from src/monodroid/jni/win32/jni_md.h rename to src/native/monodroid/win32/jni_md.h diff --git a/src/monodroid/jni/xa-internal-api-impl.hh b/src/native/monodroid/xa-internal-api-impl.hh similarity index 100% rename from src/monodroid/jni/xa-internal-api-impl.hh rename to src/native/monodroid/xa-internal-api-impl.hh diff --git a/src/monodroid/jni/xa-internal-api.cc b/src/native/monodroid/xa-internal-api.cc similarity index 100% rename from src/monodroid/jni/xa-internal-api.cc rename to src/native/monodroid/xa-internal-api.cc diff --git a/src/monodroid/jni/xa-internal-api.hh b/src/native/monodroid/xa-internal-api.hh similarity index 100% rename from src/monodroid/jni/xa-internal-api.hh rename to src/native/monodroid/xa-internal-api.hh diff --git a/src/monodroid/jni/xamarin-android-app-context.cc b/src/native/monodroid/xamarin-android-app-context.cc similarity index 100% rename from src/monodroid/jni/xamarin-android-app-context.cc rename to src/native/monodroid/xamarin-android-app-context.cc diff --git a/src/monodroid/jni/xamarin_getifaddrs.cc b/src/native/monodroid/xamarin_getifaddrs.cc similarity index 98% rename from src/monodroid/jni/xamarin_getifaddrs.cc rename to src/native/monodroid/xamarin_getifaddrs.cc index 9918bde5fa7..d2dab9643eb 100644 --- a/src/monodroid/jni/xamarin_getifaddrs.cc +++ b/src/native/monodroid/xamarin_getifaddrs.cc @@ -30,10 +30,13 @@ #endif #include "logger.hh" +#include "util.hh" #include "globals.hh" #include "xamarin_getifaddrs.h" +using namespace xamarin::android; + /* Some of these aren't defined in android's rtnetlink.h (as of ndk 16). We define values for all of * them if they aren't found so that the debug code works properly. We could skip them but future * versions of the NDK might include definitions for them. @@ -528,7 +531,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd size_t buf_size = static_cast(getpagesize ()); log_debug (LOG_NETLINK, "receive buffer size == %d", buf_size); - size_t alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, sizeof(*response), buf_size); + size_t alloc_size = Helpers::multiply_with_overflow_check (sizeof(*response), buf_size); response = (unsigned char*)malloc (alloc_size); ssize_t length = 0; if (!response) { @@ -556,7 +559,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd } #if DEBUG - if (utils.should_log (LOG_NETLINK)) { + if (Util::should_log (LOG_NETLINK)) { log_debug_nocheck (LOG_NETLINK, "response flags:"); if (netlink_reply.msg_flags == 0) log_debug_nocheck (LOG_NETLINK, " [NONE]"); @@ -818,7 +821,7 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net if (prefix_bytes + 2 < data_length) /* Set the rest of the mask bits in the byte following the last 0xFF value */ netmask_data [prefix_bytes + 1] = static_cast(0xff << (8 - (prefix_length % 8))); - if (utils.should_log (LOG_NETLINK)) { + if (Util::should_log (LOG_NETLINK)) { log_debug_nocheck (LOG_NETLINK, " netmask is: "); for (uint32_t i = 0; i < data_length; i++) { log_debug_nocheck (LOG_NETLINK, "%s%u", i == 0 ? " " : ".", (unsigned char)ifa->ifa_netmask->sa_data [i]); @@ -876,7 +879,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if } if (payload_size > 0) { - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, payload_size, room_for_trailing_null); + size_t alloc_size = Helpers::add_with_overflow_check (payload_size, room_for_trailing_null); ifa->ifa_name = (char*)malloc (alloc_size); if (!ifa->ifa_name) { goto error; @@ -1013,7 +1016,7 @@ get_link_info (const struct nlmsghdr *message) if (!ifa->ifa_name) { goto error; } - if (utils.should_log (LOG_NETLINK)) { + if (Util::should_log (LOG_NETLINK)) { log_debug_nocheck (LOG_NETLINK, " interface name (payload length: %d; string length: %d)\n", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); log_debug_nocheck (LOG_NETLINK, " %s\n", ifa->ifa_name); } @@ -1134,7 +1137,7 @@ struct enumvalue iflas[] = { static void print_ifla_name (int id) { - if (!utils.should_log (LOG_NETLINK)) + if (!Util::should_log (LOG_NETLINK)) return; int i = 0; @@ -1156,7 +1159,7 @@ print_ifla_name (int id) static void print_address_list (const char title[], struct _monodroid_ifaddrs *list) { - if (!utils.should_log (LOG_NETLINK)) + if (!Util::should_log (LOG_NETLINK)) return; struct _monodroid_ifaddrs *cur; diff --git a/src/monodroid/jni/xamarin_getifaddrs.h b/src/native/monodroid/xamarin_getifaddrs.h similarity index 100% rename from src/monodroid/jni/xamarin_getifaddrs.h rename to src/native/monodroid/xamarin_getifaddrs.h diff --git a/src/monodroid/monodroid.csproj b/src/native/native.csproj similarity index 89% rename from src/monodroid/monodroid.csproj rename to src/native/native.csproj index c4dbc2d7b5c..38b77115100 100644 --- a/src/monodroid/monodroid.csproj +++ b/src/native/native.csproj @@ -1,3 +1,4 @@ + netstandard2.0 @@ -6,15 +7,15 @@ Exe false - + $(MicrosoftAndroidSdkOutDir)lib\ - - + + diff --git a/src/monodroid/monodroid.targets b/src/native/native.targets similarity index 50% rename from src/monodroid/monodroid.targets rename to src/native/native.targets index ed667e7fc44..ab4539bd4fa 100644 --- a/src/monodroid/monodroid.targets +++ b/src/native/native.targets @@ -1,24 +1,10 @@ - - - - - <_EmbeddedBlobSource Include="config.xml" /> - <_EmbeddedBlobDestination Include="jni\config.include" /> - <_EmbeddedBlobSource Include="machine.config.xml" /> - <_EmbeddedBlobDestination Include="jni\machine.config.include" /> - - - - jni\generate-pinvoke-tables.cc - jni\pinvoke-tables.include - - + DependsOnTargets="_ConfigureRuntimes;_BuildAndroidRuntimes;_BuildAndroidAnalyzerRuntimes;_CopyToPackDirs"> + - - - - - - - - - - - + + Command="$(NinjaPath) run_static_analysis" + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> + <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="java-interop\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="libstub\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="libunwind\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="lz4\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="monodroid\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="runtime-base\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="shared\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="shared\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="tracing\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="xamarin-app-debug-helper\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="xamarin-app-stub\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-asan-Debug\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-asan-Release\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-ubsan-Debug\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-ubsan-Release\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> @@ -71,61 +52,78 @@ + DependsOnTargets="_ConfigureRuntimesInputs" + Inputs="@(_ConfigureRuntimesInputs)" + Outputs="@(_ConfigureRuntimesOutputs)"> <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - <_CmakeAndroidFlags>$(_NoInline) $(_NoStrip) --debug-output -GNinja -DCMAKE_MAKE_PROGRAM="$(NinjaPath)" -DXA_BUILD_CONFIGURATION=$(Configuration) -DXA_LIB_TOP_DIR=$(MicrosoftAndroidSdkOutDir) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DMONO_PATH="$(MonoSourceFullPath)" -DANDROID_STL="none" -DANDROID_CPP_FEATURES="no-rtti no-exceptions" -DANDROID_TOOLCHAIN=clang -DCMAKE_TOOLCHAIN_FILE="$(AndroidNdkDirectory)/build/cmake/android.toolchain.cmake" -DANDROID_NDK=$(AndroidNdkDirectory) + + <_CmakeAndroidFlags>$(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" - + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - $(_CmakeAndroidFlags) -DCONFIGURATION=Release -DCMAKE_BUILD_TYPE=Debug -DANDROID_NATIVE_API_LEVEL=%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_PLATFORM=android-%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_ABI=%(AndroidSupportedTargetJitAbi.Identity) -DANDROID_RID=%(AndroidSupportedTargetJitAbi.AndroidRID) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" "$(MSBuildThisFileDirectory)" + --preset default-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - $(_CmakeAndroidFlags) -DCONFIGURATION=Debug -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_PLATFORM=android-%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_ABI=%(AndroidSupportedTargetJitAbi.Identity) -DANDROID_RID=%(AndroidSupportedTargetJitAbi.AndroidRID) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" "$(MSBuildThisFileDirectory)" + --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - $(_CmakeAndroidFlags) -DCONFIGURATION=Release -DCMAKE_BUILD_TYPE=Debug -DENABLE_CLANG_ASAN=ON -DANDROID_STL="c++_static" -DANDROID_NATIVE_API_LEVEL=%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_PLATFORM=android-%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_ABI=%(AndroidSupportedTargetJitAbi.Identity) -DANDROID_RID=%(AndroidSupportedTargetJitAbi.AndroidRID) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" "$(MSBuildThisFileDirectory)" + --preset asan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - $(_CmakeAndroidFlags) -DCONFIGURATION=Release -DCMAKE_BUILD_TYPE=Debug -DENABLE_CLANG_UBSAN=ON -DANDROID_STL="c++_static" -DANDROID_CPP_FEATURES="rtti exceptions" -DANDROID_NATIVE_API_LEVEL=%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_PLATFORM=android-%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_ABI=%(AndroidSupportedTargetJitAbi.Identity) -DANDROID_RID=%(AndroidSupportedTargetJitAbi.AndroidRID) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" "$(MSBuildThisFileDirectory)" - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug + --preset asan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - $(_CmakeAndroidFlags) -DCONFIGURATION=Debug -DCMAKE_BUILD_TYPE=Release -DENABLE_CLANG_ASAN=ON -DANDROID_STL="c++_static" -DANDROID_NATIVE_API_LEVEL=%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_PLATFORM=android-%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_ABI=%(AndroidSupportedTargetJitAbi.Identity) -DANDROID_RID=%(AndroidSupportedTargetJitAbi.AndroidRID) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" "$(MSBuildThisFileDirectory)" - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release + --preset ubsan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - $(_CmakeAndroidFlags) -DCONFIGURATION=Debug -DCMAKE_BUILD_TYPE=Release -DENABLE_CLANG_UBSAN=ON -DANDROID_STL="c++_static" -DANDROID_CPP_FEATURES="rtti exceptions" -DANDROID_NATIVE_API_LEVEL=%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_PLATFORM=android-%(AndroidSupportedTargetJitAbi.ApiLevelNET) -DANDROID_ABI=%(AndroidSupportedTargetJitAbi.Identity) -DANDROID_RID=%(AndroidSupportedTargetJitAbi.AndroidRID) -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$(OutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)" "$(MSBuildThisFileDirectory)" + --preset ubsan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release + + + - <_MonoDroidSources Include="jni\*.cc;jni\*.h;jni\*.hh;jni\**\*.c;" /> + <_MonoDroidSources Include="libstub\*.cc;libstub\*.hh" /> + <_MonoDroidSources Include="monodroid\*.cc;monodroid\*.hh" /> + <_MonoDroidSources Include="runtime-base\*.cc;runtime-base\*.hh" /> + <_MonoDroidSources Include="shared\*.cc;shared\*.hh" /> + <_MonoDroidSources Include="tracing\*.cc;tracing\*.hh" /> + <_MonoDroidSources Include="xamarin-app-stub\*.cc;xamarin-app-stub\*.hh" /> + <_MonoDroidSources Include="xamarin-debug-app-helper\*.cc;xamarin-debug-app-helper\*.hh" /> + <_MonoDroidSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> + <_MonoDroidSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> + DependsOnTargets="_FindMonoDroidSources"> <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> @@ -145,46 +143,40 @@ + DependsOnTargets="_BuildAndroidRuntimesInputs;_TestPinvokeTables" + Inputs="@(_BuildAndroidRuntimesInputs)" + Outputs="@(_BuildAndroidRuntimesOutputs)"> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> + Condition=" '$(EnableNativeAnalyzers)' == 'true' " + DependsOnTargets="_BuildAndroidRuntimesInputs" + Inputs="@(_BuildAndroidRuntimesInputs)" + Outputs="@(_BuildAndroidAnalyzerRuntimesOutputs)"> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug" /> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug" /> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release" /> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release" /> @@ -193,12 +185,11 @@ AfterTargets="Clean"> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug"/> + WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release"/> + @@ -208,37 +199,10 @@ - - - - - - <_CompileCommandsDir Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug"> - %(AndroidSupportedTargetJitAbi.AndroidRID)-Debug - - <_CompileCommandsDir Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release"> - %(AndroidSupportedTargetJitAbi.AndroidRID)-Release - - - - - - - $(AndroidNdkDirectory)\toolchains\llvm\prebuilt\$(NdkLlvmTag)\bin\clang-tidy - - - + DependsOnTargets="Build"> @@ -248,25 +212,22 @@ <_x86RuntimePackFiles Include="$(OutputPath)\android-x86\*.*" /> <_x64RuntimePackFiles Include="$(OutputPath)\android-x64\*.*" /> + + SkipUnchangedFiles="true" /> + SkipUnchangedFiles="true" /> + SkipUnchangedFiles="true" /> + SkipUnchangedFiles="true" /> diff --git a/src/native/runtime-base/CMakeLists.txt b/src/native/runtime-base/CMakeLists.txt new file mode 100644 index 00000000000..85e75163f60 --- /dev/null +++ b/src/native/runtime-base/CMakeLists.txt @@ -0,0 +1,61 @@ +set(LIB_NAME runtime-base) +set(LIB_ALIAS xa::runtime-base) + +set(XA_RUNTIME_BASE_SOURCES + android-system.cc + cpu-arch-detect.cc + logger.cc + shared-constants.cc + util.cc +) +add_clang_check_sources("${XA_RUNTIME_BASE_SOURCES}") + +list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS + -ffunction-sections + -fdata-sections +) + +xa_check_c_args(RUNTIME_BASE_CXX_ARGS "${POTENTIAL_LOCAL_COMPILER_ARGS}") + +add_library( + ${LIB_NAME} + STATIC + ${XA_RUNTIME_BASE_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} + ${RUNTIME_BASE_CXX_ARGS} +) + +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" +) + +target_include_directories( + ${LIB_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} +) + +target_link_libraries( + ${LIB_NAME} + PRIVATE + ${SHARED_LIB_NAME} + xa::xamarin-app +) + +set_target_properties( + ${LIB_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/monodroid/jni/android-system.cc b/src/native/runtime-base/android-system.cc similarity index 69% rename from src/monodroid/jni/android-system.cc rename to src/native/runtime-base/android-system.cc index fce00bae049..cdc73976dd9 100644 --- a/src/monodroid/jni/android-system.cc +++ b/src/native/runtime-base/android-system.cc @@ -3,13 +3,27 @@ #include #include -#include "globals.hh" +#include + #include "android-system.hh" -#include "jni-wrappers.hh" -#include "xamarin-app.hh" #include "cpp-util.hh" #include "java-interop-dlfcn.h" #include "java-interop.h" +#include "jni-wrappers.hh" +#include "shared-constants.hh" +#include "strings.hh" +#include "util.hh" +#include "xamarin-app.hh" + +using namespace microsoft::java_interop; +using namespace xamarin::android::internal; +using namespace xamarin::android; + +// These two must stay here until JavaInterop is converted to C++ +FILE *gref_log; +FILE *lref_log; +bool gref_to_logcat; +bool lref_to_logcat; #if defined (DEBUG) namespace xamarin::android::internal { @@ -20,17 +34,11 @@ namespace xamarin::android::internal { struct BundledProperty *next; }; } -#endif // DEBUG - -using namespace microsoft::java_interop; -using namespace xamarin::android; -using namespace xamarin::android::internal; -#if defined (DEBUG) BundledProperty *AndroidSystem::bundled_properties = nullptr; BundledProperty* -AndroidSystem::lookup_system_property (const char *name) +AndroidSystem::lookup_system_property (const char *name) noexcept { for (BundledProperty *p = bundled_properties; p != nullptr; p = p->next) { if (strcmp (p->name, name) == 0) { @@ -42,7 +50,7 @@ AndroidSystem::lookup_system_property (const char *name) #endif // DEBUG const char* -AndroidSystem::lookup_system_property (const char *name, size_t &value_len) +AndroidSystem::lookup_system_property (const char *name, size_t &value_len) noexcept { value_len = 0; #if defined (DEBUG) @@ -85,7 +93,7 @@ AndroidSystem::lookup_system_property (const char *name, size_t &value_len) #if defined (DEBUG) void -AndroidSystem::add_system_property (const char *name, const char *value) +AndroidSystem::add_system_property (const char *name, const char *value) noexcept { BundledProperty* p = lookup_system_property (name); if (p != nullptr) { @@ -99,7 +107,7 @@ AndroidSystem::add_system_property (const char *name, const char *value) } size_t name_len = strlen (name); - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, sizeof (BundledProperty), name_len + 1); + size_t alloc_size = Helpers::add_with_overflow_check (sizeof (BundledProperty), name_len + 1); p = reinterpret_cast (malloc (alloc_size)); if (p == nullptr) return; @@ -122,14 +130,14 @@ AndroidSystem::add_system_property (const char *name, const char *value) #endif // DEBUG int -AndroidSystem::_monodroid__system_property_get (const char *name, char *sp_value, size_t sp_value_len) +AndroidSystem::_monodroid__system_property_get (const char *name, char *sp_value, size_t sp_value_len) noexcept { if (name == nullptr || sp_value == nullptr) return -1; char *buf = nullptr; if (sp_value_len < PROPERTY_VALUE_BUFFER_LEN) { - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, PROPERTY_VALUE_BUFFER_LEN, 1); + size_t alloc_size = Helpers::add_with_overflow_check (PROPERTY_VALUE_BUFFER_LEN, 1); log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only %u bytes", sp_value_len); buf = new char [alloc_size]; } @@ -145,7 +153,7 @@ AndroidSystem::_monodroid__system_property_get (const char *name, char *sp_value } int -AndroidSystem::monodroid_get_system_property (const char *name, dynamic_local_string& value) +AndroidSystem::monodroid_get_system_property (const char *name, dynamic_local_string& value) noexcept { int len = _monodroid__system_property_get (name, value.get (), value.size ()); if (len > 0) { @@ -160,11 +168,11 @@ AndroidSystem::monodroid_get_system_property (const char *name, dynamic_local_st return len; value.assign (v, plen); - return ADD_WITH_OVERFLOW_CHECK (int, plen, 0); + return Helpers::add_with_overflow_check (plen, 0); } int -AndroidSystem::monodroid_get_system_property (const char *name, char **value) +AndroidSystem::monodroid_get_system_property (const char *name, char **value) noexcept { if (value) *value = nullptr; @@ -183,7 +191,7 @@ AndroidSystem::monodroid_get_system_property (const char *name, char **value) } if (len >= 0 && value) { - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, static_cast(len), 1); + size_t alloc_size = Helpers::add_with_overflow_check (static_cast(len), 1); *value = new char [alloc_size]; if (*value == nullptr) return -len; @@ -196,12 +204,12 @@ AndroidSystem::monodroid_get_system_property (const char *name, char **value) #if defined (DEBUG) size_t -AndroidSystem::_monodroid_get_system_property_from_file (const char *path, char **value) +AndroidSystem::_monodroid_get_system_property_from_file (const char *path, char **value) noexcept { if (value != nullptr) *value = nullptr; - FILE* fp = utils.monodroid_fopen (path, "r"); + FILE* fp = Util::monodroid_fopen (path, "r"); if (fp == nullptr) return 0; @@ -217,7 +225,7 @@ AndroidSystem::_monodroid_get_system_property_from_file (const char *path, char return file_size + 1; } - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, file_size, 1); + size_t alloc_size = Helpers::add_with_overflow_check (file_size, 1); *value = new char[alloc_size]; size_t len = fread (*value, 1, file_size, fp); @@ -233,7 +241,7 @@ AndroidSystem::_monodroid_get_system_property_from_file (const char *path, char #endif // def DEBUG size_t -AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] const char *name, [[maybe_unused]] char ** value) +AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] const char *name, [[maybe_unused]] char ** value) noexcept { #if defined (DEBUG) for (const char *od : override_dirs) { @@ -241,7 +249,7 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co continue; } - std::unique_ptr override_file {utils.path_combine (od, name)}; + std::unique_ptr override_file {Util::path_combine (od, name)}; log_info (LOG_DEFAULT, "Trying to get property from %s", override_file.get ()); size_t result = _monodroid_get_system_property_from_file (override_file.get (), value); if (result == 0 || value == nullptr || (*value) == nullptr || **value == '\0') { @@ -256,7 +264,7 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co // TODO: review this. Do we really have to create the dir in release? void -AndroidSystem::create_update_dir (char *override_dir) +AndroidSystem::create_update_dir (char *override_dir) noexcept { #if defined (RELEASE) /* @@ -266,23 +274,23 @@ AndroidSystem::create_update_dir (char *override_dir) * However, if any logging is enabled (which should _not_ happen with * pre-loaded apps!), we need the .__override__ directory... */ - if (log_categories == 0 && monodroid_get_system_property (Debug::DEBUG_MONO_PROFILE_PROPERTY, nullptr) == 0) { + if (log_categories == 0 && monodroid_get_system_property (SharedConstants::DEBUG_MONO_PROFILE_PROPERTY, nullptr) == 0) { return; } #endif // def RELEASE override_dirs [0] = override_dir; - utils.create_public_directory (override_dir); + Util::create_public_directory (override_dir); log_warn (LOG_DEFAULT, "Creating public update directory: `%s`", override_dir); } bool -AndroidSystem::get_full_dso_path (const char *base_dir, const char *dso_path, dynamic_local_string& path) +AndroidSystem::get_full_dso_path (const char *base_dir, const char *dso_path, dynamic_local_string& path) noexcept { if (dso_path == nullptr) return false; - if (base_dir == nullptr || utils.is_path_rooted (dso_path)) + if (base_dir == nullptr || Util::is_path_rooted (dso_path)) return const_cast(dso_path); // Absolute path or no base path, can't do much with it path.assign_c (base_dir) @@ -293,27 +301,27 @@ AndroidSystem::get_full_dso_path (const char *base_dir, const char *dso_path, dy } void* -AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check) +AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check) noexcept { if (path == nullptr || *path == '\0') return nullptr; log_info (LOG_ASSEMBLY, "Trying to load shared library '%s'", path); - if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !utils.file_exists (path)) { + if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { log_info (LOG_ASSEMBLY, "Shared library '%s' not found", path); return nullptr; } char *error = nullptr; void *handle = java_interop_lib_load (path, dl_flags, &error); - if (handle == nullptr && utils.should_log (LOG_ASSEMBLY)) + if (handle == nullptr && Util::should_log (LOG_ASSEMBLY)) log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '%s'. %s", path, error); java_interop_free (error); return handle; } void* -AndroidSystem::load_dso_from_specified_dirs (const char **directories, size_t num_entries, const char *dso_name, unsigned int dl_flags) +AndroidSystem::load_dso_from_specified_dirs (const char **directories, size_t num_entries, const char *dso_name, unsigned int dl_flags) noexcept { abort_if_invalid_pointer_argument (directories); if (dso_name == nullptr) @@ -333,13 +341,13 @@ AndroidSystem::load_dso_from_specified_dirs (const char **directories, size_t nu } void* -AndroidSystem::load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags) +AndroidSystem::load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags) noexcept { return load_dso_from_specified_dirs (app_lib_directories.data (), app_lib_directories.size (), name, dl_flags); } void* -AndroidSystem::load_dso_from_override_dirs ([[maybe_unused]] const char *name, [[maybe_unused]] unsigned int dl_flags) +AndroidSystem::load_dso_from_override_dirs ([[maybe_unused]] const char *name, [[maybe_unused]] unsigned int dl_flags) noexcept { #ifdef RELEASE return nullptr; @@ -349,7 +357,7 @@ AndroidSystem::load_dso_from_override_dirs ([[maybe_unused]] const char *name, [ } void* -AndroidSystem::load_dso_from_any_directories (const char *name, unsigned int dl_flags) +AndroidSystem::load_dso_from_any_directories (const char *name, unsigned int dl_flags) noexcept { void *handle = load_dso_from_override_dirs (name, dl_flags); if (handle == nullptr) @@ -358,16 +366,16 @@ AndroidSystem::load_dso_from_any_directories (const char *name, unsigned int dl_ } bool -AndroidSystem::get_existing_dso_path_on_disk (const char *base_dir, const char *dso_name, dynamic_local_string& path) +AndroidSystem::get_existing_dso_path_on_disk (const char *base_dir, const char *dso_name, dynamic_local_string& path) noexcept { - if (get_full_dso_path (base_dir, dso_name, path) && utils.file_exists (path.get ())) + if (get_full_dso_path (base_dir, dso_name, path) && Util::file_exists (path.get ())) return true; return false; } bool -AndroidSystem::get_full_dso_path_on_disk (const char *dso_name, dynamic_local_string& path) +AndroidSystem::get_full_dso_path_on_disk (const char *dso_name, dynamic_local_string& path) noexcept { if (is_embedded_dso_mode_enabled ()) return false; @@ -390,7 +398,7 @@ AndroidSystem::get_full_dso_path_on_disk (const char *dso_name, dynamic_local_st } int -AndroidSystem::count_override_assemblies (void) +AndroidSystem::count_override_assemblies (void) noexcept { int c = 0; @@ -398,14 +406,14 @@ AndroidSystem::count_override_assemblies (void) DIR *dir; dirent *e; - if (dir_path == nullptr || !utils.directory_exists (dir_path)) + if (dir_path == nullptr || !Util::directory_exists (dir_path)) continue; if ((dir = ::opendir (dir_path)) == nullptr) continue; while ((e = ::readdir (dir)) != nullptr && e) { - if (utils.monodroid_dirent_hasextension (e, ".dll")) + if (Util::monodroid_dirent_hasextension (e, ".dll")) ++c; } ::closedir (dir); @@ -415,7 +423,7 @@ AndroidSystem::count_override_assemblies (void) } long -AndroidSystem::get_max_gref_count_from_system (void) +AndroidSystem::get_max_gref_count_from_system (void) noexcept { long max; @@ -426,7 +434,7 @@ AndroidSystem::get_max_gref_count_from_system (void) } dynamic_local_string override; - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_MAX_GREFC, override) > 0) { + if (monodroid_get_system_property (SharedConstants::DEBUG_MONO_MAX_GREFC, override) > 0) { char *e; max = strtol (override.get (), &e, 10); switch (*e) { @@ -442,7 +450,7 @@ AndroidSystem::get_max_gref_count_from_system (void) if (max < 0) max = std::numeric_limits::max (); if (*e) { - log_warn (LOG_GC, "Unsupported '%s' value '%s'.", Debug::DEBUG_MONO_MAX_GREFC.data (), override.get ()); + log_warn (LOG_GC, "Unsupported '%s' value '%s'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); } log_warn (LOG_GC, "Overriding max JNI Global Reference count to %i", max); } @@ -450,7 +458,7 @@ AndroidSystem::get_max_gref_count_from_system (void) } long -AndroidSystem::get_gref_gc_threshold () +AndroidSystem::get_gref_gc_threshold () noexcept { if (max_gref_count == std::numeric_limits::max ()) return max_gref_count; @@ -459,7 +467,7 @@ AndroidSystem::get_gref_gc_threshold () #if defined (DEBUG) void -AndroidSystem::setup_environment (const char *name, const char *value) +AndroidSystem::setup_environment (const char *name, const char *value) noexcept { if (name == nullptr || *name == '\0') return; @@ -478,7 +486,7 @@ AndroidSystem::setup_environment (const char *name, const char *value) } void -AndroidSystem::setup_environment_from_override_file (const char *path) +AndroidSystem::setup_environment_from_override_file (const char *path) noexcept { using read_count_type = size_t; @@ -568,7 +576,7 @@ AndroidSystem::setup_environment_from_override_file (const char *path) #endif // def DEBUG void -AndroidSystem::setup_environment () +AndroidSystem::setup_environment () noexcept { if (is_mono_aot_enabled () && *mono_aot_mode_name != '\0') { switch (mono_aot_mode_name [0]) { @@ -632,8 +640,8 @@ AndroidSystem::setup_environment () #if defined (DEBUG) // TODO: for debug read from file in the override directory named `environment` for (const char *od : override_dirs) { - std::unique_ptr env_override_file {utils.path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; - if (utils.file_exists (env_override_file.get ())) { + std::unique_ptr env_override_file {Util::path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; + if (Util::file_exists (env_override_file.get ())) { setup_environment_from_override_file (env_override_file.get ()); } } @@ -641,7 +649,7 @@ AndroidSystem::setup_environment () } void -AndroidSystem::setup_process_args_apk (const char *apk, size_t index, size_t apk_count, [[maybe_unused]] void *user_data) +AndroidSystem::setup_process_args_apk (const char *apk, size_t index, size_t apk_count, [[maybe_unused]] void *user_data) noexcept { if (apk == nullptr || index != apk_count - 1) return; @@ -651,7 +659,110 @@ AndroidSystem::setup_process_args_apk (const char *apk, size_t index, size_t apk } void -AndroidSystem::setup_process_args (jstring_array_wrapper &runtimeApks) +AndroidSystem::setup_process_args (jstring_array_wrapper &runtimeApks) noexcept +{ + for_each_apk (runtimeApks, static_cast (&AndroidSystem::setup_process_args_apk), nullptr); +} + +void +AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept +{ + // appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX] points to the native library directory + std::unique_ptr libmonodroid_path {Util::path_combine (appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr (), "libmonodroid.so")}; + log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to %s", libmonodroid_path.get ()); + if (!Util::file_exists (libmonodroid_path.get ())) { + log_debug (LOG_ASSEMBLY, "%s not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); + set_embedded_dso_mode_enabled (true); + } else { + log_debug (LOG_ASSEMBLY, "Native libs extracted to %s, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + set_embedded_dso_mode_enabled (false); + } +} + +void +AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) noexcept +{ + if (!is_embedded_dso_mode_enabled ()) { + log_debug (LOG_DEFAULT, "Setting up for DSO lookup in app data directories"); + + AndroidSystem::app_lib_directories = std::span (single_app_lib_directory); + AndroidSystem::app_lib_directories [0] = Util::strdup_new (appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: %s", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + } else { + log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"); + + if (have_split_apks) { + // If split apks are used, then we will have just a single app library directory. Don't allocate any memory + // dynamically in this case + AndroidSystem::app_lib_directories = std::span (single_app_lib_directory); + } else { + size_t app_lib_directories_size = have_split_apks ? 1 : runtimeApks.get_length (); + AndroidSystem::app_lib_directories = std::span (new const char*[app_lib_directories_size], app_lib_directories_size); + } + + unsigned short built_for_cpu = 0, running_on_cpu = 0; + unsigned char is64bit = 0; + _monodroid_detect_cpu_and_architecture (&built_for_cpu, &running_on_cpu, &is64bit); + setup_apk_directories (running_on_cpu, runtimeApks, have_split_apks); + } +} + +void +AndroidSystem::for_each_apk (jstring_array_wrapper &runtimeApks, ForEachApkHandler handler, void *user_data) noexcept +{ + size_t apksLength = runtimeApks.get_length (); + for (size_t i = 0; i < apksLength; ++i) { + jstring_wrapper &e = runtimeApks [i]; + + (handler) (e.get_cstr (), i, apksLength, user_data); + } +} + +force_inline void +AndroidSystem::add_apk_libdir (const char *apk, size_t &index, const char *abi) noexcept +{ + abort_unless (index < app_lib_directories.size (), "Index out of range"); + app_lib_directories [index] = Util::string_concat (apk, "!/lib/", abi); + log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: %s", app_lib_directories[index]); + index++; +} + +force_inline void +AndroidSystem::setup_apk_directories (unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks, bool have_split_apks) noexcept { - for_each_apk (runtimeApks, static_cast (&AndroidSystem::setup_process_args_apk), nullptr); + const char *abi = android_abi_names [running_on_cpu]; + size_t number_of_added_directories = 0; + + for (size_t i = 0; i < runtimeApks.get_length (); ++i) { + jstring_wrapper &e = runtimeApks [i]; + const char *apk = e.get_cstr (); + + if (have_split_apks) { + if (Util::ends_with (apk, SharedConstants::split_config_abi_apk_name)) { + add_apk_libdir (apk, number_of_added_directories, abi); + break; + } + } else { + add_apk_libdir (apk, number_of_added_directories, abi); + } + } + + if (app_lib_directories.size () == number_of_added_directories) [[likely]] { + return; + } + + abort_unless (number_of_added_directories > 0, "At least a single application lib directory must be added"); + app_lib_directories = app_lib_directories.subspan (0, number_of_added_directories); +} + +char* +AndroidSystem::determine_primary_override_dir (jstring_wrapper &home) noexcept +{ + dynamic_local_string name { home.get_cstr () }; + name.append ("/") + .append (SharedConstants::OVERRIDE_DIRECTORY_NAME) + .append ("/") + .append (SharedConstants::android_lib_abi); + + return Util::strdup_new (name.get ()); } diff --git a/src/native/runtime-base/android-system.hh b/src/native/runtime-base/android-system.hh new file mode 100644 index 00000000000..f100c6ff028 --- /dev/null +++ b/src/native/runtime-base/android-system.hh @@ -0,0 +1,233 @@ +#ifndef ANDROID_SYSTEM_HH +#define ANDROID_SYSTEM_HH + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "xamarin-app.hh" +#include "cpu-arch.hh" +#include "jni-wrappers.hh" +#include "strings.hh" + +static inline constexpr size_t PROPERTY_VALUE_BUFFER_LEN = PROP_VALUE_MAX + 1; + +extern FILE *gref_log; +extern FILE *lref_log; +extern bool gref_to_logcat; +extern bool lref_to_logcat; + +namespace xamarin::android { + class jstring_wrapper; + class jstring_array_wrapper; +} + +namespace xamarin::android::internal { +#if defined (DEBUG) + struct BundledProperty; +#endif + + class AndroidSystem + { + protected: + using ForEachApkHandler = void (*) (const char *apk, size_t index, size_t apk_count, void *user_data); + + private: +#if defined (__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc99-designator" +#endif + // Values correspond to the CPU_KIND_* macros + static constexpr const char* android_abi_names[CPU_KIND_X86_64+1] = { + [0] = "unknown", + [CPU_KIND_ARM] = "armeabi-v7a", + [CPU_KIND_ARM64] = "arm64-v8a", + [CPU_KIND_MIPS] = "mips", + [CPU_KIND_X86] = "x86", + [CPU_KIND_X86_64] = "x86_64", + }; +#if defined (__clang__) +#pragma clang diagnostic pop +#endif + static constexpr size_t ANDROID_ABI_NAMES_SIZE = sizeof(android_abi_names) / sizeof (android_abi_names[0]); + +#if defined (DEBUG) + static constexpr std::string_view OVERRIDE_ENVIRONMENT_FILE_NAME { "environment" }; + static constexpr uint32_t OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE = 22; + static BundledProperty *bundled_properties; +#endif + + public: +#ifdef ANDROID64 + static constexpr std::string_view SYSTEM_LIB_PATH { "/system/lib64" }; +#else + static constexpr std::string_view SYSTEM_LIB_PATH { "/system/lib" }; +#endif + + inline static std::array override_dirs{}; + + // This optimizes things a little bit. The array is allocated at build time, so we pay no cost for its + // allocation and at run time it allows us to skip dynamic memory allocation. + inline static std::array single_app_lib_directory{}; + inline static std::span app_lib_directories; + + public: + static void setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) noexcept; + + static size_t monodroid_get_system_property_from_overrides (const char *name, char ** value) noexcept; + static char* get_bundled_app (JNIEnv *env, jstring dir) noexcept; + static int count_override_assemblies () noexcept; + static long get_gref_gc_threshold () noexcept; + static void* load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check) noexcept; + static void* load_dso_from_any_directories (const char *name, unsigned int dl_flags) noexcept; + static bool get_full_dso_path_on_disk (const char *dso_name, dynamic_local_string& path) noexcept; + static void setup_environment () noexcept; + static void setup_process_args (jstring_array_wrapper &runtimeApks) noexcept; + static void create_update_dir (char *override_dir) noexcept; + static int monodroid_get_system_property (const char *name, char **value) noexcept; + static int monodroid_get_system_property (const char *name, dynamic_local_string &value) noexcept; + + static int monodroid_get_system_property (std::string_view const& name, char **value) noexcept + { + return monodroid_get_system_property (name.data (), value); + } + + static int monodroid_get_system_property (std::string_view const& name, dynamic_local_string& value) noexcept + { + return monodroid_get_system_property (name.data (), value); + } + + static void set_override_dir (uint32_t index, const char* dir) noexcept + { + if (index >= override_dirs.size ()) + return; + + override_dirs [index] = const_cast (dir); + } + + static bool is_embedded_dso_mode_enabled () noexcept + { + return embedded_dso_mode_enabled; + } + + static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; + + static char *get_runtime_libdir () noexcept + { + return runtime_libdir; + } + + static void set_runtime_libdir (char *dir) noexcept + { + runtime_libdir = dir; + } + + static char *get_primary_override_dir () noexcept + { + return primary_override_dir; + } + + static void set_primary_override_dir (jstring_wrapper& home) noexcept + { + primary_override_dir = determine_primary_override_dir (home); + } + + static long get_max_gref_count () noexcept + { + return max_gref_count; + } + + static void init_max_gref_count () noexcept + { + max_gref_count = get_max_gref_count_from_system (); + } + + static bool is_assembly_preload_enabled () noexcept + { + return application_config.uses_assembly_preload; + } + + static bool is_mono_llvm_enabled () noexcept + { + return application_config.uses_mono_llvm; + } + + static bool is_mono_aot_enabled () noexcept + { + return application_config.uses_mono_aot; + } + + static MonoAotMode get_mono_aot_mode () noexcept + { + return aotMode; + } + + static bool is_interpreter_enabled () noexcept + { + return get_mono_aot_mode () == MonoAotMode::MONO_AOT_MODE_INTERP_ONLY; + } + + // Hack, see comment for `aot_mode_last_is_interpreter` at the bottom of the class declaration + static bool is_aot_mode_last_really_interpreter_mode () noexcept + { + return false; + } + + static void set_running_in_emulator (bool yesno) noexcept + { + running_in_emulator = yesno; + } + + protected: + static void for_each_apk (jstring_array_wrapper &runtimeApks, ForEachApkHandler handler, void *user_data) noexcept; + + private: +#if defined (DEBUG) + static void add_system_property (const char *name, const char *value) noexcept; + static void setup_environment (const char *name, const char *value) noexcept; + static void setup_environment_from_override_file (const char *path) noexcept; + static BundledProperty* lookup_system_property (const char *name) noexcept; +#endif + static const char* lookup_system_property (const char *name, size_t &value_len) noexcept; + static long get_max_gref_count_from_system () noexcept; + static void setup_process_args_apk (const char *apk, size_t index, size_t apk_count, void *user_data) noexcept; + static int _monodroid__system_property_get (const char *name, char *sp_value, size_t sp_value_len) noexcept; +#if defined (DEBUG) + static size_t _monodroid_get_system_property_from_file (const char *path, char **value) noexcept; +#endif + static bool get_full_dso_path (const char *base_dir, const char *dso_path, dynamic_local_string& path) noexcept; + static void* load_dso_from_specified_dirs (const char **directories, size_t num_entries, const char *dso_name, unsigned int dl_flags) noexcept; + static void* load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags) noexcept; + static void* load_dso_from_override_dirs (const char *name, unsigned int dl_flags) noexcept; + static bool get_existing_dso_path_on_disk (const char *base_dir, const char *dso_name, dynamic_local_string& path) noexcept; + + private: + static void add_apk_libdir (const char *apk, size_t &index, const char *abi) noexcept; + static void setup_apk_directories (unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks, bool have_split_apks) noexcept; + static char* determine_primary_override_dir (jstring_wrapper &home) noexcept; + + static void set_embedded_dso_mode_enabled (bool yesno) noexcept + { + embedded_dso_mode_enabled = yesno; + } + + private: + static inline bool embedded_dso_mode_enabled = false; + static inline char *runtime_libdir = nullptr; + static inline char *primary_override_dir = nullptr; + static inline long max_gref_count = 0; + static inline MonoAotMode aotMode = MonoAotMode::MONO_AOT_MODE_NONE; + static inline bool running_in_emulator = false; + }; +} +#endif // !ANDROID_SYSTEM_HH diff --git a/src/monodroid/jni/cpu-arch-detect.cc b/src/native/runtime-base/cpu-arch-detect.cc similarity index 100% rename from src/monodroid/jni/cpu-arch-detect.cc rename to src/native/runtime-base/cpu-arch-detect.cc diff --git a/src/monodroid/jni/cpu-arch.hh b/src/native/runtime-base/cpu-arch.hh similarity index 95% rename from src/monodroid/jni/cpu-arch.hh rename to src/native/runtime-base/cpu-arch.hh index 29c210d47f4..de0e9cf93d5 100644 --- a/src/monodroid/jni/cpu-arch.hh +++ b/src/native/runtime-base/cpu-arch.hh @@ -1,8 +1,6 @@ #ifndef __CPU_ARCH_H #define __CPU_ARCH_H -#include - #define CPU_KIND_UNKNOWN ((unsigned short)0) #define CPU_KIND_ARM ((unsigned short)1) #define CPU_KIND_ARM64 ((unsigned short)2) diff --git a/src/monodroid/jni/jni-wrappers.hh b/src/native/runtime-base/jni-wrappers.hh similarity index 100% rename from src/monodroid/jni/jni-wrappers.hh rename to src/native/runtime-base/jni-wrappers.hh diff --git a/src/native/runtime-base/logger.cc b/src/native/runtime-base/logger.cc new file mode 100644 index 00000000000..4f39b25ff6b --- /dev/null +++ b/src/native/runtime-base/logger.cc @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "android-system.hh" +#include "cpp-util.hh" +#include "logger.hh" +#include "shared-constants.hh" +#include "util.hh" + +using namespace xamarin::android; +using namespace xamarin::android::internal; + +namespace { + FILE* + open_file (LogCategories category, const char *path, const char *override_dir, const char *filename) + { + char *p = NULL; + FILE *f; + + if (path && access (path, W_OK) < 0) { + log_warn (category, "Could not open path '%s' for logging (\"%s\"). Using '%s/%s' instead.", + path, strerror (errno), override_dir, filename); + path = NULL; + } + + if (!path) { + Util::create_public_directory (override_dir); + p = Util::path_combine (override_dir, filename); + path = p; + } + + unlink (path); + + f = Util::monodroid_fopen (path, "a"); + + if (f) { + Util::set_world_accessable (path); + } else { + log_warn (category, "Could not open path '%s' for logging: %s", path, strerror (errno)); + } + + free (p); + + return f; + } + + + const char *gref_file = nullptr; + const char *lref_file = nullptr; + bool light_gref = false; + bool light_lref = false; +} + +#if defined(DEBUG) +void +Logger::set_debugger_log_level (const char *level) noexcept +{ + if (level == nullptr || *level == '\0') { + _got_debugger_log_level = false; + return; + } + + unsigned long v = strtoul (level, nullptr, 0); + if (v == std::numeric_limits::max () && errno == ERANGE) { + log_error (LOG_DEFAULT, "Invalid debugger log level value '%s', expecting a positive integer or zero", level); + return; + } + + if (v > std::numeric_limits::max ()) { + log_warn (LOG_DEFAULT, "Debugger log level value is higher than the maximum of %u, resetting to the maximum value.", std::numeric_limits::max ()); + v = std::numeric_limits::max (); + } + + _got_debugger_log_level = true; + _debugger_log_level = static_cast(v); +} +#endif // def DEBUG + +void +Logger::init_reference_logging (const char *override_dir) noexcept +{ + if ((log_categories & LOG_GREF) != 0 && !light_gref) { + gref_log = open_file (LOG_GREF, gref_file, override_dir, "grefs.txt"); + } + + if ((log_categories & LOG_LREF) != 0 && !light_lref) { + // if both lref & gref have files specified, and they're the same path, reuse the FILE*. + if (lref_file != nullptr && strcmp (lref_file, gref_file != nullptr ? gref_file : "") == 0) { + lref_log = gref_log; + } else { + lref_log = open_file (LOG_LREF, lref_file, override_dir, "lrefs.txt"); + } + } +} + +force_inline bool +Logger::set_category (std::string_view const& name, string_segment& arg, unsigned int entry, bool arg_starts_with_name) noexcept +{ + if ((log_categories & entry) == entry) { + return false; + } + + if (arg_starts_with_name ? arg.starts_with (name) : arg.equal (name)) { + log_categories |= entry; + return true; + } + + return false; +} + +void +Logger::init_logging_categories (char*& mono_log_mask, char*& mono_log_level) noexcept +{ + mono_log_mask = nullptr; + mono_log_level = nullptr; + _log_timing_categories = LogTimingCategories::Default; + + dynamic_local_string value; + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_LOG_PROPERTY, value) == 0) + return; + + string_segment param; + while (value.next_token (',', param)) { + constexpr std::string_view CAT_ALL { "all" }; + + if (param.equal (CAT_ALL)) { + log_categories = 0xFFFFFFFF; + break; + } + + if (set_category ("assembly", param, LOG_ASSEMBLY)) { + continue; + } + + if (set_category ("default", param, LOG_DEFAULT)) { + continue; + } + + if (set_category ("debugger", param, LOG_DEBUGGER)) { + continue; + } + + if (set_category ("gc", param, LOG_GC)) { + continue; + } + + if (set_category ("gref", param, LOG_GREF)) { + continue; + } + + if (set_category ("lref", param, LOG_LREF)) { + continue; + } + + if (set_category ("timing", param, LOG_TIMING)) { + continue; + } + + if (set_category ("network", param, LOG_NET)) { + continue; + } + + if (set_category ("netlink", param, LOG_NETLINK)) { + continue; + } + + constexpr std::string_view CAT_GREF_EQUALS { "gref=" }; + if (set_category (CAT_GREF_EQUALS, param, LOG_GREF, true /* arg_starts_with_name */)) { + gref_file = Util::strdup_new (param, CAT_GREF_EQUALS.length ()); + continue; + } + + if (set_category ("gref-", param, LOG_GREF)) { + light_gref = true; + continue; + } + + if (set_category ("gref+", param, LOG_GREF)) { + gref_to_logcat = true; + continue; + } + + constexpr std::string_view CAT_LREF_EQUALS { "lref=" }; + if (set_category (CAT_LREF_EQUALS, param, LOG_LREF, true /* arg_starts_with_name */)) { + lref_file = Util::strdup_new (param, CAT_LREF_EQUALS.length ()); + continue; + } + + if (set_category ("lref-", param, LOG_LREF)) { + light_lref = true; + continue; + } + + if (set_category ("lref+", param, LOG_LREF)) { + lref_to_logcat = true; + continue; + } + + if (param.starts_with ("timing=fast-bare")) { + log_categories |= LOG_TIMING; + _log_timing_categories |= LogTimingCategories::FastBare; + continue; + } + + if (param.starts_with ("timing=bare")) { + log_categories |= LOG_TIMING; + _log_timing_categories |= LogTimingCategories::Bare; + continue; + } + + constexpr std::string_view MONO_LOG_MASK_ARG { "mono_log_mask=" }; + if (param.starts_with (MONO_LOG_MASK_ARG)) { + mono_log_mask = Util::strdup_new (param, MONO_LOG_MASK_ARG.length ()); + continue; + } + + constexpr std::string_view MONO_LOG_LEVEL_ARG { "mono_log_level=" }; + if (param.starts_with (MONO_LOG_LEVEL_ARG)) { + mono_log_level = Util::strdup_new (param, MONO_LOG_LEVEL_ARG.length ()); + continue; + } + +#if defined (DEBUG) + constexpr std::string_view DEBUGGER_LOG_LEVEL { "debugger-log-level=" }; + if (param.starts_with (DEBUGGER_LOG_LEVEL)) { + dynamic_local_string level; + level.assign (param.start () + DEBUGGER_LOG_LEVEL.length (), param.length () - DEBUGGER_LOG_LEVEL.length ()); + set_debugger_log_level (level.get ()); + } +#endif + } + +#if DEBUG + if ((log_categories & LOG_GC) != 0) + _gc_spew_enabled = 1; +#endif /* DEBUG */ +} diff --git a/src/native/runtime-base/logger.hh b/src/native/runtime-base/logger.hh new file mode 100644 index 00000000000..2111c628bdd --- /dev/null +++ b/src/native/runtime-base/logger.hh @@ -0,0 +1,57 @@ +#ifndef __MONODROID_LOGGER_H__ +#define __MONODROID_LOGGER_H__ + +#include + +#include "log_types.hh" +#include "strings.hh" + +namespace xamarin::android { + class Logger + { + public: + static void init_logging_categories (char*& mono_log_mask, char*& mono_log_level) noexcept; + static void init_reference_logging (const char *override_dir) noexcept; + + static LogTimingCategories log_timing_categories () noexcept + { + return _log_timing_categories; + } + +#if defined(DEBUG) + static void set_debugger_log_level (const char *level) noexcept; + + static bool have_debugger_log_level () noexcept + { + return _got_debugger_log_level; + } + + static int get_debugger_log_level () noexcept + { + return _debugger_log_level; + } + + static void set_gc_spew_enabled (int yesno) noexcept + { + _gc_spew_enabled = yesno; + } + + static int gc_spew_enabled () noexcept + { + return _gc_spew_enabled; + } +#endif // def DEBUG + + private: + static bool set_category (std::string_view const& name, internal::string_segment& arg, unsigned int entry, bool arg_starts_with_name = false) noexcept; + + private: + static inline LogTimingCategories _log_timing_categories; +#if defined(DEBUG) + static inline bool _got_debugger_log_level = false; + static inline int _debugger_log_level = 0; + static inline int _gc_spew_enabled = 0; +#endif // def DEBUG + }; +} +#endif diff --git a/src/monodroid/jni/shared-constants.cc b/src/native/runtime-base/shared-constants.cc similarity index 100% rename from src/monodroid/jni/shared-constants.cc rename to src/native/runtime-base/shared-constants.cc diff --git a/src/monodroid/jni/shared-constants.hh b/src/native/runtime-base/shared-constants.hh similarity index 66% rename from src/monodroid/jni/shared-constants.hh rename to src/native/runtime-base/shared-constants.hh index 2c706ae2df7..bc8461f59f0 100644 --- a/src/monodroid/jni/shared-constants.hh +++ b/src/native/runtime-base/shared-constants.hh @@ -46,6 +46,21 @@ namespace xamarin::android::internal static constexpr std::string_view MONO_SGEN_ARCH_SO { "libmonosgen-" __BITNESS__ "-2.0.so" }; static constexpr std::string_view OVERRIDE_DIRECTORY_NAME { ".__override__" }; + /* Android property containing connection information, set by XS */ + static inline constexpr std::string_view DEBUG_MONO_CONNECT_PROPERTY { "debug.mono.connect" }; + static inline constexpr std::string_view DEBUG_MONO_DEBUG_PROPERTY { "debug.mono.debug" }; + static inline constexpr std::string_view DEBUG_MONO_ENV_PROPERTY { "debug.mono.env" }; + static inline constexpr std::string_view DEBUG_MONO_EXTRA_PROPERTY { "debug.mono.extra" }; + static inline constexpr std::string_view DEBUG_MONO_GC_PROPERTY { "debug.mono.gc" }; + static inline constexpr std::string_view DEBUG_MONO_GDB_PROPERTY { "debug.mono.gdb" }; + static inline constexpr std::string_view DEBUG_MONO_LOG_PROPERTY { "debug.mono.log" }; + static inline constexpr std::string_view DEBUG_MONO_MAX_GREFC { "debug.mono.max_grefc" }; + static inline constexpr std::string_view DEBUG_MONO_PROFILE_PROPERTY { "debug.mono.profile" }; + static inline constexpr std::string_view DEBUG_MONO_RUNTIME_ARGS_PROPERTY { "debug.mono.runtime_args" }; + static inline constexpr std::string_view DEBUG_MONO_SOFT_BREAKPOINTS { "debug.mono.soft_breakpoints" }; + static inline constexpr std::string_view DEBUG_MONO_TRACE_PROPERTY { "debug.mono.trace" }; + static inline constexpr std::string_view DEBUG_MONO_WREF_PROPERTY { "debug.mono.wref" }; + #if __arm__ static constexpr std::string_view android_abi { "armeabi_v7a" }; static constexpr std::string_view android_lib_abi { "armeabi-v7a" }; @@ -83,6 +98,19 @@ namespace xamarin::android::internal // Documented in NDK's comments static constexpr size_t MAX_LOGCAT_MESSAGE_LENGTH = 1023; + + static constexpr std::string_view LOG_CATEGORY_NAME_NONE { "*none*" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID { "monodroid" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_ASSEMBLY { "monodroid-assembly" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_DEBUG { "monodroid-debug" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_GC { "monodroid-gc" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_GREF { "monodroid-gref" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_LREF { "monodroid-lref" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_TIMING { "monodroid-timing" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_BUNDLE { "monodroid-bundle" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_NETWORK { "monodroid-network" }; + static constexpr std::string_view LOG_CATEGORY_NAME_MONODROID_NETLINK { "monodroid-netlink" }; + static constexpr std::string_view LOG_CATEGORY_NAME_ERROR { "*error*" }; }; } #endif // __SHARED_CONSTANTS_HH diff --git a/src/monodroid/jni/strings.hh b/src/native/runtime-base/strings.hh similarity index 98% rename from src/monodroid/jni/strings.hh rename to src/native/runtime-base/strings.hh index 97f22e0b805..a552abd345c 100644 --- a/src/monodroid/jni/strings.hh +++ b/src/native/runtime-base/strings.hh @@ -776,7 +776,7 @@ namespace xamarin::android::internal force_inline void ensure_have_extra (size_t length) noexcept { - size_t needed_space = ADD_WITH_OVERFLOW_CHECK (size_t, length, idx + 1); + size_t needed_space = Helpers::add_with_overflow_check (length, idx + 1); if (needed_space > buffer.size ()) { log_fatal ( LOG_DEFAULT, @@ -790,11 +790,11 @@ namespace xamarin::android::internal force_inline void resize_for_extra (size_t needed_space) noexcept { if constexpr (TStorage::has_resize) { - size_t required_space = ADD_WITH_OVERFLOW_CHECK (size_t, needed_space, idx + 1); + size_t required_space = Helpers::add_with_overflow_check (needed_space, idx + 1); size_t current_size = buffer.size (); if (required_space > current_size) { - size_t new_size = ADD_WITH_OVERFLOW_CHECK (size_t, current_size, (current_size / 2)); - new_size = ADD_WITH_OVERFLOW_CHECK (size_t, new_size, required_space); + size_t new_size = Helpers::add_with_overflow_check (current_size, (current_size / 2)); + new_size = Helpers::add_with_overflow_check (new_size, required_space); buffer.resize (new_size); } } diff --git a/src/monodroid/jni/basic-utilities.cc b/src/native/runtime-base/util.cc similarity index 55% rename from src/monodroid/jni/basic-utilities.cc rename to src/native/runtime-base/util.cc index bfe10dfa922..892d7fe5343 100644 --- a/src/monodroid/jni/basic-utilities.cc +++ b/src/native/runtime-base/util.cc @@ -1,15 +1,120 @@ #include -#include #include +#include +#include +#include + +#include +#include +#include -#include "basic-utilities.hh" -#include "logger.hh" -#include "cpp-util.hh" +#include +#include +#include + +#include "util.hh" using namespace xamarin::android; +void Util::initialize () noexcept +{ + page_size = getpagesize (); +} + +int +Util::send_uninterrupted (int fd, void *buf, size_t len) +{ + ssize_t res; + + do { + res = send (fd, buf, len, 0); + } while (res == -1 && errno == EINTR); + + return static_cast(res) == len; +} + +ssize_t +Util::recv_uninterrupted (int fd, void *buf, size_t len) +{ + using nbytes_type = size_t; + + ssize_t res; + size_t total = 0; + int flags = 0; + nbytes_type nbytes; + + do { + nbytes = static_cast(len - total); + res = recv (fd, (char *) buf + total, nbytes, flags); + + if (res > 0) + total += static_cast(res); + } while ((res > 0 && total < len) || (res == -1 && errno == EINTR)); + + return static_cast(total); +} + +MonoAssembly* +Util::monodroid_load_assembly (MonoAssemblyLoadContextGCHandle alc_handle, const char *basename) +{ + MonoImageOpenStatus status; + MonoAssemblyName *aname = mono_assembly_name_new (basename); + MonoAssembly *assm = mono_assembly_load_full_alc (alc_handle, aname, nullptr, &status); + + mono_assembly_name_free (aname); + + if (assm == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { + log_fatal (LOG_DEFAULT, "Unable to find assembly '%s'.", basename); + Helpers::abort_application (); + } + return assm; +} + +MonoAssembly * +Util::monodroid_load_assembly (MonoDomain *domain, const char *basename) +{ + MonoAssembly *assm; + MonoAssemblyName *aname; + MonoImageOpenStatus status; + + aname = mono_assembly_name_new (basename); + MonoDomain *current = get_current_domain (); + + if (domain != current) { + mono_domain_set (domain, FALSE); + assm = mono_assembly_load_full (aname, nullptr, &status, 0); + mono_domain_set (current, FALSE); + } else { + assm = mono_assembly_load_full (aname, nullptr, &status, 0); + } + + mono_assembly_name_free (aname); + + if (!assm) { + log_fatal (LOG_DEFAULT, "Unable to find assembly '%s'.", basename); + Helpers::abort_application (); + } + return assm; +} + +MonoClass* +Util::monodroid_get_class_from_name ([[maybe_unused]] MonoDomain *domain, const char* assembly, const char *_namespace, const char *type) +{ + MonoClass *result; + MonoAssemblyName *aname = mono_assembly_name_new (assembly); + MonoAssembly *assm = mono_assembly_loaded (aname); + if (assm != nullptr) { + MonoImage *image = mono_assembly_get_image (assm); + result = mono_class_from_name (image, _namespace, type); + } else + result = nullptr; + + mono_assembly_name_free (aname); + return result; +} + char* -BasicUtilities::path_combine (const char *path1, const char *path2) +Util::path_combine (const char *path1, const char *path2) { // Don't let erroneous nullptr parameters situation propagate abort_unless (path1 != nullptr || path2 != nullptr, "At least one path must be a valid pointer"); @@ -19,7 +124,7 @@ BasicUtilities::path_combine (const char *path1, const char *path2) if (path2 == nullptr) return strdup_new (path1); - size_t len = ADD_WITH_OVERFLOW_CHECK (size_t, strlen (path1), strlen (path2) + 2); + size_t len = Helpers::add_with_overflow_check (strlen (path1), strlen (path2) + 2); char *ret = new char [len]; *ret = '\0'; @@ -31,7 +136,7 @@ BasicUtilities::path_combine (const char *path1, const char *path2) } void -BasicUtilities::create_public_directory (const char *dir) +Util::create_public_directory (const char *dir) { mode_t m = umask (0); int ret = mkdir (dir, 0777); @@ -42,7 +147,7 @@ BasicUtilities::create_public_directory (const char *dir) } int -BasicUtilities::create_directory (const char *pathname, mode_t mode) +Util::create_directory (const char *pathname, mode_t mode) { if (mode <= 0) mode = DEFAULT_DIRECTORY_MODE; @@ -76,7 +181,7 @@ BasicUtilities::create_directory (const char *pathname, mode_t mode) } void -BasicUtilities::set_world_accessable ([[maybe_unused]] const char *path) +Util::set_world_accessable ([[maybe_unused]] const char *path) { int r; do { @@ -89,7 +194,7 @@ BasicUtilities::set_world_accessable ([[maybe_unused]] const char *path) } void -BasicUtilities::set_user_executable ([[maybe_unused]] const char *path) +Util::set_user_executable ([[maybe_unused]] const char *path) { int r; do { @@ -102,7 +207,7 @@ BasicUtilities::set_user_executable ([[maybe_unused]] const char *path) } bool -BasicUtilities::file_exists (const char *file) +Util::file_exists (const char *file) { struct stat s; if (::stat (file, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG) @@ -111,7 +216,7 @@ BasicUtilities::file_exists (const char *file) } bool -BasicUtilities::directory_exists (const char *directory) +Util::directory_exists (const char *directory) { if (directory == nullptr) { return false; @@ -124,15 +229,15 @@ BasicUtilities::directory_exists (const char *directory) } bool -BasicUtilities::file_copy (const char *to, const char *from) +Util::file_copy (const char *to, const char *from) { if (to == nullptr || *to == '\0') { - log_error (LOG_DEFAULT, "BasicUtilities::file_copy: `to` parameter must not be null or empty"); + log_error (LOG_DEFAULT, "Util::file_copy: `to` parameter must not be null or empty"); return false; } if (from == nullptr || *from == '\0') { - log_error (LOG_DEFAULT, "BasicUtilities::file_copy: `from` parameter must not be null or empty"); + log_error (LOG_DEFAULT, "Util::file_copy: `from` parameter must not be null or empty"); return false; } @@ -165,7 +270,7 @@ BasicUtilities::file_copy (const char *to, const char *from) } bool -BasicUtilities::is_path_rooted (const char *path) +Util::is_path_rooted (const char *path) noexcept { if (path == nullptr) { return false; @@ -175,7 +280,7 @@ BasicUtilities::is_path_rooted (const char *path) } FILE * -BasicUtilities::monodroid_fopen (const char *filename, const char *mode) +Util::monodroid_fopen (const char *filename, const char *mode) { FILE *ret; @@ -192,13 +297,13 @@ BasicUtilities::monodroid_fopen (const char *filename, const char *mode) } int -BasicUtilities::monodroid_dirent_hasextension (dirent *e, const char *extension) +Util::monodroid_dirent_hasextension (dirent *e, const char *extension) { return ends_with_slow (e->d_name, extension); } void -BasicUtilities::monodroid_strfreev (char **str_array) +Util::monodroid_strfreev (char **str_array) { char **orig = str_array; if (str_array == nullptr) { @@ -213,7 +318,7 @@ BasicUtilities::monodroid_strfreev (char **str_array) } char ** -BasicUtilities::monodroid_strsplit (const char *str, const char *delimiter, size_t max_tokens) +Util::monodroid_strsplit (const char *str, const char *delimiter, size_t max_tokens) { if (str == nullptr || *str == '\0') { return static_cast(xcalloc (sizeof(char*), 1)); @@ -236,7 +341,7 @@ BasicUtilities::monodroid_strsplit (const char *str, const char *delimiter, size size_t vector_size = (max_tokens > 0 && tokens_in_str >= max_tokens) ? max_tokens + 1 : tokens_in_str + 2; // Includes the terminating 'nullptr` entry - char **vector = static_cast(xmalloc (MULTIPLY_WITH_OVERFLOW_CHECK (size_t, sizeof(char*), vector_size))); + char **vector = static_cast(xmalloc (Helpers::multiply_with_overflow_check (sizeof(char*), vector_size))); size_t vector_idx = 0; while (*str != '\0' && !(max_tokens > 0 && vector_idx + 1 >= max_tokens)) { @@ -258,7 +363,7 @@ BasicUtilities::monodroid_strsplit (const char *str, const char *delimiter, size } size_t toklen = static_cast((str - c)); - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, toklen, 1); + size_t alloc_size = Helpers::add_with_overflow_check (toklen, 1); char *token = static_cast(xmalloc (alloc_size)); strncpy (token, c, toklen); token [toklen] = '\0'; @@ -286,7 +391,7 @@ BasicUtilities::monodroid_strsplit (const char *str, const char *delimiter, size } char * -BasicUtilities::monodroid_strdup_printf (const char *format, ...) +Util::monodroid_strdup_printf (const char *format, ...) { va_list args; @@ -298,7 +403,7 @@ BasicUtilities::monodroid_strdup_printf (const char *format, ...) } char* -BasicUtilities::monodroid_strdup_vprintf (const char *format, va_list vargs) +Util::monodroid_strdup_vprintf (const char *format, va_list vargs) { char *ret = nullptr; int n = vasprintf (&ret, format, vargs); diff --git a/src/native/runtime-base/util.hh b/src/native/runtime-base/util.hh new file mode 100644 index 00000000000..718e2e87551 --- /dev/null +++ b/src/native/runtime-base/util.hh @@ -0,0 +1,401 @@ +// This is a -*- C++ -*- header +#ifndef __MONODROID_UTIL_H__ +#define __MONODROID_UTIL_H__ + +#ifndef TRUE +#ifdef __cplusplus +static inline constexpr int TRUE = 1; +#else +#define TRUE 1 +#endif // __cplusplus +#endif + +#ifndef FALSE +#ifdef __cplusplus +static inline constexpr int FALSE = 0; +#else +#define FALSE 0 +#endif // __cplusplus +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "jni-wrappers.hh" +#include "java-interop-util.h" +#include "logger.hh" +#include "strings.hh" + +#ifdef __cplusplus +namespace xamarin::android +{ + class Util + { + static constexpr std::array hex_chars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + static constexpr uint32_t ms_in_nsec = 1000000ULL; + + public: + static void initialize () noexcept; + + static int monodroid_getpagesize () noexcept + { + return page_size; + } + + static MonoAssembly *monodroid_load_assembly (MonoDomain *domain, const char *basename); + static MonoAssembly *monodroid_load_assembly (MonoAssemblyLoadContextGCHandle alc_handle, const char *basename); + static MonoClass *monodroid_get_class_from_name (MonoDomain *domain, const char* assembly, const char *_namespace, const char *type); + static int send_uninterrupted (int fd, void *buf, size_t len); + static ssize_t recv_uninterrupted (int fd, void *buf, size_t len); + static FILE *monodroid_fopen (const char* filename, const char* mode); + static int monodroid_dirent_hasextension (dirent *e, const char *extension); + static void monodroid_strfreev (char **str_array); + static char **monodroid_strsplit (const char *str, const char *delimiter, size_t max_tokens); + static char *monodroid_strdup_printf (const char *format, ...); + static char *monodroid_strdup_vprintf (const char *format, va_list vargs); + static char* path_combine (const char *path1, const char *path2); + static void create_public_directory (const char *dir); + static int create_directory (const char *pathname, mode_t mode); + static void set_world_accessable (const char *path); + static void set_user_executable (const char *path); + static bool file_exists (const char *file); + static bool directory_exists (const char *directory); + static bool file_copy (const char *to, const char *from); + + static std::optional get_file_size_at (int dirfd, const char *file_name) noexcept + { + struct stat sbuf; + if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { + log_warn (LOG_ASSEMBLY, "Failed to stat file '%s': %s", file_name, std::strerror (errno)); + return std::nullopt; + } + + return static_cast(sbuf.st_size); + } + + static std::optional open_file_ro_at (int dirfd, const char *file_name) noexcept + { + int fd = openat (dirfd, file_name, O_RDONLY); + if (fd < 0) { + log_error (LOG_ASSEMBLY, "Failed to open file '%s' for reading: %s", file_name, std::strerror (errno)); + return std::nullopt; + } + + return fd; + } + + // Make sure that `buf` has enough space! This is by design, the methods are supposed to be fast. + template + static void path_combine (TBuffer& buf, const char* path1, const char* path2) noexcept + { + path_combine (buf, path1, path1 == nullptr ? 0 : strlen (path1), path2, path2 == nullptr ? 0 : strlen (path2)); + } + + // internal::static_local_string + template + static void path_combine (TBuffer& buf, const char* path1, size_t path1_len, const char* path2, size_t path2_len) noexcept + { + abort_unless (path1 != nullptr || path2 != nullptr, "At least one path must be a valid pointer"); + + if (path1 == nullptr) { + buf.append_c (path2); + return; + } + + if (path2 == nullptr) { + buf.append_c (path1); + return; + } + + buf.append (path1, path1_len); + buf.append ("/"); + buf.append (path2, path2_len); + } + + template + static void path_combine (internal::static_local_string& buf, const char* path1, const char* path2) noexcept + { + path_combine (buf, path1, path2); + } + + template + static void path_combine (internal::static_local_string& buf, const char* path1, size_t path1_len, const char* path2, size_t path2_len) noexcept + { + path_combine (buf, path1, path1_len, path2, path2_len); + } + + template + static void path_combine (internal::dynamic_local_string& buf, const char* path1, const char* path2) noexcept + { + path_combine (buf, path1, path2); + } + + template + static void path_combine (internal::dynamic_local_string& buf, const char* path1, size_t path1_len, const char* path2, size_t path2_len) noexcept + { + path_combine (buf, path1, path1_len, path2, path2_len); + } + + static char* path_combine (const char *path1, std::string_view const& path2) noexcept + { + return path_combine (path1, path2.data ()); + } + + static bool ends_with_slow (const char *str, const char *end) noexcept + { + char *p = const_cast (strstr (str, end)); + return p != nullptr && p [strlen (end)] == '\0'; + } + + template + static bool ends_with (internal::dynamic_local_string const& str, std::string_view const& sv) noexcept + { + if (str.length () < sv.length ()) { + return false; + } + + return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; + } + + static bool ends_with (const char *str, std::string_view const& sv) noexcept + { + size_t len = strlen (str); + if (len < sv.length ()) { + return false; + } + + return memcmp (str + len - sv.length (), sv.data (), sv.length ()) == 0; + } + + template + static bool ends_with (const char *str, const char (&end)[N]) + { + char *p = const_cast (strstr (str, end)); + return p != nullptr && p [N - 1] == '\0'; + } + + template + static bool ends_with (const char *str, std::array const& end) noexcept + { + char *p = const_cast (strstr (str, end.data ())); + return p != nullptr && p [N - 1] == '\0'; + } + + template + static bool ends_with (const char *str, helper_char_array const& end) noexcept + { + char *p = const_cast (strstr (str, end.data ())); + return p != nullptr && p [N - 1] == '\0'; + } + + template + static bool ends_with (internal::string_base const& str, const char (&end)[N]) noexcept + { + constexpr size_t end_length = N - 1; + + size_t len = str.length (); + if (len < end_length) [[unlikely]] { + return false; + } + + return memcmp (str.get () + len - end_length, end, end_length) == 0; + } + + template + static bool ends_with (internal::string_base const& str, std::array const& end) noexcept + { + constexpr size_t end_length = N - 1; + + size_t len = str.length (); + if (len < end_length) [[unlikely]] { + return false; + } + + return memcmp (str.get () + len - end_length, end.data (), end_length) == 0; + } + + template + static bool ends_with (internal::string_base const& str, helper_char_array const& end) noexcept + { + constexpr size_t end_length = N - 1; + + size_t len = str.length (); + if (len < end_length) [[unlikely]] { + return false; + } + + return memcmp (str.get () + len - end_length, end.data (), end_length) == 0; + } + + template + static const TChar* find_last (internal::string_base const& str, const char ch) noexcept + { + if (str.empty ()) { + return nullptr; + } + + for (size_t i = str.length (); i > 0; i--) { + const size_t index = i - 1; + if (str[index] == ch) { + return str.get () + index; + } + } + + return nullptr; + } + + static void *xmalloc (size_t size) noexcept + { + return ::xmalloc (size); + } + + static void *xrealloc (void *ptr, size_t size) noexcept + { + return ::xrealloc (ptr, size); + } + + static void *xcalloc (size_t nmemb, size_t size) noexcept + { + return ::xcalloc (nmemb, size); + } + + static char *strdup_new (const char* s, size_t len) noexcept + { + if (len == 0 || s == nullptr) [[unlikely]] { + return nullptr; + } + + size_t alloc_size = Helpers::add_with_overflow_check (len, 1); + auto ret = new char[alloc_size]; + memcpy (ret, s, len); + ret[len] = '\0'; + + return ret; + } + + static char *strdup_new (const char* s) noexcept + { + if (s == nullptr) [[unlikely]] { + return nullptr; + } + + return strdup_new (s, strlen (s)); + } + + template + static char *strdup_new (internal::dynamic_local_string const& buf) noexcept + { + return strdup_new (buf.get (), buf.length ()); + } + + static char *strdup_new (xamarin::android::internal::string_segment const& s, size_t from_index = 0) noexcept + { + if (from_index >= s.length ()) { + return nullptr; + } + + return strdup_new (s.start () + from_index, s.length () - from_index); + } + + template + static char* string_concat (const char *s1, const CharType* s2, Strings... strings) noexcept + { + assert_char_type (); + + size_t len = calculate_length (s1, s2, strings...); + + char *ret = new char [len + 1]; + *ret = '\0'; + + concatenate_strings_into (len, ret, s1, s2, strings...); + + return ret; + } + + static bool is_path_rooted (const char *path) noexcept; + + template + static size_t calculate_length (const CharType* s) noexcept + { + return strlen (s); + } + + template + static size_t calculate_length (const CharType* s1, Strings... strings) noexcept + { + assert_char_type (); + + return strlen (s1) + calculate_length (strings...); + } + + static bool should_log (LogCategories category) noexcept + { + return (log_categories & category) != 0; + } + + static MonoDomain *get_current_domain (bool attach_thread_if_needed = true) noexcept + { + MonoDomain *ret = mono_domain_get (); + if (ret != nullptr) { + return ret; + } + + // It's likely that we got a nullptr because the current thread isn't attached (see + // https://github.com/xamarin/xamarin-android/issues/6211), so we need to attach the thread to the root + // domain + ret = mono_get_root_domain (); + if (attach_thread_if_needed) { + mono_thread_attach (ret); + } + + return ret; + } + + protected: + template + static constexpr void concatenate_strings_into ([[maybe_unused]] size_t len, [[maybe_unused]] char *dest) noexcept + {} + + template + static constexpr void concatenate_strings_into (size_t len, char *dest, const CharType* s1, Strings... strings) noexcept + { + assert_char_type (); + + strcat (dest, s1); + concatenate_strings_into (len, dest, strings...); + } + + static int make_directory (const char *path, [[maybe_unused]] mode_t mode) noexcept + { + return ::mkdir (path, mode); + } + + private: + template + static constexpr void assert_char_type () + { + static_assert (std::is_same_v, "CharType must be an 8-bit character type"); + } + + private: + static inline int page_size; + }; +} +#endif // __cplusplus +#endif /* __MONODROID_UTIL_H__ */ diff --git a/src/native/shared/CMakeLists.txt b/src/native/shared/CMakeLists.txt new file mode 100644 index 00000000000..6deaaaf9d79 --- /dev/null +++ b/src/native/shared/CMakeLists.txt @@ -0,0 +1,77 @@ +set(LIB_NAME xa-shared-bits) +set(LIB_ALIAS xa::shared) + +set(LIB_NAME_NO_ABI ${LIB_NAME}-no-abi) +set(LIB_ALIAS_NO_ABI ${LIB_ALIAS}-no-abi) + +set(XA_SHARED_CXX_ABI_SOURCES + cxx-abi/string.cc + cxx-abi/terminate.cc +) + +set(XA_SHARED_SOURCES + helpers.cc + log_functions.cc + new_delete.cc +) +add_clang_check_sources("${XA_SHARED_SOURCES};${XA_SHARED_CXX_ABI_SOURCES}") + +set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") +set(CONSTEXPR_XXH3_DIR "${EXTERNAL_DIR}/constexpr-xxh3") + +add_library( + ${LIB_NAME} + STATIC + ${XA_SHARED_SOURCES} + ${XA_SHARED_CXX_ABI_SOURCES} +) +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +add_library( + ${LIB_NAME_NO_ABI} + STATIC + ${XA_SHARED_SOURCES} +) +add_library(${LIB_ALIAS_NO_ABI} ALIAS ${LIB_NAME_NO_ABI}) + +macro(lib_target_options TARGET_NAME) + target_include_directories( + ${TARGET_NAME} + PUBLIC + "$" + "$" + "$" + "$" + ) + + target_link_libraries( + ${TARGET_NAME} + PUBLIC + xa::java-interop + -llog + ) + + target_include_directories( + ${TARGET_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} + ) + + target_compile_options( + ${TARGET_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} + ) + + set_target_properties( + ${TARGET_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) + + xa_add_compile_definitions(${TARGET_NAME}) +endmacro() + +lib_target_options(${LIB_NAME}) +lib_target_options(${LIB_NAME_NO_ABI}) diff --git a/src/monodroid/jni/cpp-util.hh b/src/native/shared/cpp-util.hh similarity index 87% rename from src/monodroid/jni/cpp-util.hh rename to src/native/shared/cpp-util.hh index 8f50149eb33..3ac87f9de82 100644 --- a/src/monodroid/jni/cpp-util.hh +++ b/src/native/shared/cpp-util.hh @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -33,19 +34,31 @@ do_abort_unless (const char* fmt, ...) #define abort_if_invalid_pointer_argument(_ptr_) abort_unless ((_ptr_) != nullptr, "Parameter '%s' must be a valid pointer", #_ptr_) #define abort_if_negative_integer_argument(_arg_) abort_unless ((_arg_) > 0, "Parameter '%s' must be larger than 0", #_arg_) -// Helpers to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any -// of the macros present. -#define PD_LOG_LOCATION() log_info_nocheck (LOG_DEFAULT, "loc: %s:%d (%s)", __FILE__, __LINE__, __FUNCTION__) -#define PD_LOG_FUNCTION() log_info_nocheck (LOG_DEFAULT, "%s [%s:%d]", __PRETTY_FUNCTION__, __FILE__, __LINE__) +// Helper to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any +// of the calls present. +force_inline inline void pd_log_location (std::source_location sloc = std::source_location::current ()) noexcept +{ + log_info_nocheck (LOG_DEFAULT, "loc: %s:%u ('%s')", sloc.file_name (), sloc.line (), sloc.function_name ()); +} namespace xamarin::android { template struct CDeleter final { + using UnderlyingType = std::remove_cv_t; + void operator() (T* p) { - std::free (p); + UnderlyingType *ptr; + + if constexpr (std::is_const_v) { + ptr = const_cast*> (p); + } else { + ptr = p; + } + + std::free (reinterpret_cast(ptr)); } }; diff --git a/src/monodroid/jni/cppcompat.hh b/src/native/shared/cppcompat.hh similarity index 100% rename from src/monodroid/jni/cppcompat.hh rename to src/native/shared/cppcompat.hh diff --git a/src/monodroid/jni/cxx-abi/string.cc b/src/native/shared/cxx-abi/string.cc similarity index 100% rename from src/monodroid/jni/cxx-abi/string.cc rename to src/native/shared/cxx-abi/string.cc diff --git a/src/monodroid/jni/cxx-abi/terminate.cc b/src/native/shared/cxx-abi/terminate.cc similarity index 100% rename from src/monodroid/jni/cxx-abi/terminate.cc rename to src/native/shared/cxx-abi/terminate.cc diff --git a/src/native/shared/helpers.cc b/src/native/shared/helpers.cc new file mode 100644 index 00000000000..5ccd7bd4e3f --- /dev/null +++ b/src/native/shared/helpers.cc @@ -0,0 +1,19 @@ +#include "helpers.hh" + +using namespace xamarin::android; + +[[noreturn]] void +Helpers::abort_application (bool log_location, std::source_location sloc) noexcept +{ + if (log_location) { + log_fatal ( + LOG_DEFAULT, + "Abort at %s:%u:%u ('%s')", + sloc.file_name (), + sloc.line (), + sloc.column (), + sloc.function_name () + ); + } + std::abort (); +} diff --git a/src/native/shared/helpers.hh b/src/native/shared/helpers.hh new file mode 100644 index 00000000000..ba576d0fef2 --- /dev/null +++ b/src/native/shared/helpers.hh @@ -0,0 +1,46 @@ +#ifndef __HELPERS_HH +#define __HELPERS_HH + +#include +#include + +#include +#include "platform-compat.hh" + +namespace xamarin::android +{ + class [[gnu::visibility("hidden")]] Helpers + { + public: + template + force_inline static Ret add_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept + { + constexpr bool DoNotLogLocation = false; + Ret ret; + + if (__builtin_add_overflow (a, b, &ret)) [[unlikely]] { + log_fatal (LOG_DEFAULT, "Integer overflow on addition at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (DoNotLogLocation, sloc); + } + + return ret; + } + + template + force_inline static Ret multiply_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept + { + constexpr bool DoNotLogLocation = false; + Ret ret; + + if (__builtin_mul_overflow (a, b, &ret)) [[unlikely]] { + log_fatal (LOG_DEFAULT, "Integer overflow on multiplication at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (DoNotLogLocation, sloc); + } + + return ret; + } + + [[noreturn]] static void abort_application (bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; + }; +} +#endif // __HELPERS_HH diff --git a/src/native/shared/log_functions.cc b/src/native/shared/log_functions.cc new file mode 100644 index 00000000000..114bc0186e7 --- /dev/null +++ b/src/native/shared/log_functions.cc @@ -0,0 +1,120 @@ +#include +#include + +#include + +#include "java-interop-logger.h" +#include "log_types.hh" + +// Must match the same ordering as LogCategories +static constexpr std::array log_names = { + "*none*", + "monodroid", + "monodroid-assembly", + "monodroid-debug", + "monodroid-gc", + "monodroid-gref", + "monodroid-lref", + "monodroid-timing", + "monodroid-bundle", + "monodroid-network", + "monodroid-netlink", + "*error*", +}; + +#if defined(__i386__) && defined(__GNUC__) +#define ffs(__value__) __builtin_ffs ((__value__)) +#elif defined(__x86_64__) && defined(__GNUC__) +#define ffs(__value__) __builtin_ffsll ((__value__)) +#endif + +// ffs(value) returns index of lowest bit set in `value` +#define CATEGORY_NAME(value) (value == 0 ? log_names [0] : log_names [static_cast(ffs (value))]) + +unsigned int log_categories = LOG_NONE; + +#undef DO_LOG +#define DO_LOG(_level_,_category_,_format_,_args_) \ + va_start ((_args_), (_format_)); \ + __android_log_vprint ((_level_), CATEGORY_NAME((_category_)), (_format_), (_args_)); \ + va_end ((_args_)); + +void +log_error (LogCategories category, const char *format, ...) +{ + va_list args; + + DO_LOG (ANDROID_LOG_ERROR, category, format, args); +} + +void +log_fatal (LogCategories category, const char *format, ...) +{ + va_list args; + + DO_LOG (ANDROID_LOG_FATAL, category, format, args); +} + +void +log_info_nocheck (LogCategories category, const char *format, ...) +{ + va_list args; + + if ((log_categories & category) == 0) + return; + + DO_LOG (ANDROID_LOG_INFO, category, format, args); +} + +void +log_warn (LogCategories category, const char *format, ...) +{ + va_list args; + + DO_LOG (ANDROID_LOG_WARN, category, format, args); +} + +void +log_debug_nocheck (LogCategories category, const char *format, ...) +{ + va_list args; + + if ((log_categories & category) == 0) + return; + + DO_LOG (ANDROID_LOG_DEBUG, category, format, args); +} + +constexpr android_LogPriority DEFAULT_PRIORITY = ANDROID_LOG_INFO; + +// relies on the fact that the LogLevel enum has sequential values +static constexpr android_LogPriority loglevel_map[] = { + DEFAULT_PRIORITY, // Unknown + DEFAULT_PRIORITY, // Default + ANDROID_LOG_VERBOSE, // Verbose + ANDROID_LOG_DEBUG, // Debug + ANDROID_LOG_INFO, // Info + ANDROID_LOG_WARN, // Warn + ANDROID_LOG_ERROR, // Error + ANDROID_LOG_FATAL, // Fatal + ANDROID_LOG_SILENT, // Silent +}; + +static constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1; + +namespace xamarin::android { + void + log_write (LogCategories category, LogLevel level, const char *message) noexcept + { + size_t map_index = static_cast(level); + android_LogPriority priority; + + if (map_index > loglevel_map_max_index) { + priority = DEFAULT_PRIORITY; + } else { + priority = loglevel_map[map_index]; + } + + __android_log_write (priority, CATEGORY_NAME (category), message); + } +} diff --git a/src/native/shared/log_types.hh b/src/native/shared/log_types.hh new file mode 100644 index 00000000000..b0ed20018d9 --- /dev/null +++ b/src/native/shared/log_types.hh @@ -0,0 +1,35 @@ +#if !defined(LOG_LEVEL_HH) +#define LOG_LEVEL_HH + +#include + +#include "java-interop-logger.h" + +namespace xamarin::android { + enum class LogTimingCategories : uint32_t + { + Default = 0, + Bare = 1 << 0, + FastBare = 1 << 1, + }; + + // Keep in sync with LogLevel defined in JNIEnv.cs + enum class LogLevel : unsigned int + { + Unknown = 0x00, + Default = 0x01, + Verbose = 0x02, + Debug = 0x03, + Info = 0x04, + Warn = 0x05, + Error = 0x06, + Fatal = 0x07, + Silent = 0x08 + }; + + // A slightly faster alternative to other log functions as it doesn't parse the message + // for format placeholders nor it uses variable arguments + void log_write (LogCategories category, LogLevel level, const char *message) noexcept; +} +extern unsigned int log_categories; +#endif // ndef LOG_LEVEL_HH diff --git a/src/monodroid/jni/new_delete.cc b/src/native/shared/new_delete.cc similarity index 97% rename from src/monodroid/jni/new_delete.cc rename to src/native/shared/new_delete.cc index 074dfe35610..dcd3eb1d20d 100644 --- a/src/monodroid/jni/new_delete.cc +++ b/src/native/shared/new_delete.cc @@ -22,7 +22,9 @@ operator new (size_t size) { void* p = do_alloc (size); if (p == nullptr) { +#if !defined (XAMARIN_TRACING) log_fatal (LOG_DEFAULT, "Out of memory in the `new` operator"); +#endif xamarin::android::Helpers::abort_application (); } diff --git a/src/monodroid/jni/platform-compat.hh b/src/native/shared/platform-compat.hh similarity index 100% rename from src/monodroid/jni/platform-compat.hh rename to src/native/shared/platform-compat.hh diff --git a/src/monodroid/jni/xxhash.hh b/src/native/shared/xxhash.hh similarity index 100% rename from src/monodroid/jni/xxhash.hh rename to src/native/shared/xxhash.hh diff --git a/src/native/tracing/CMakeLists.txt b/src/native/tracing/CMakeLists.txt new file mode 100644 index 00000000000..cc91cb2fa78 --- /dev/null +++ b/src/native/tracing/CMakeLists.txt @@ -0,0 +1,74 @@ +set(LIB_NAME xamarin-native-tracing) +set(LIB_ALIAS xa::native-tracing) + +set(NATIVE_TRACING_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") +set(NATIVE_TRACING_INCLUDE_DIRS "${NATIVE_TRACING_INCLUDE_DIRS}" PARENT_SCOPE) + +set(XAMARIN_TRACING_SOURCES + native-tracing.cc +) +add_clang_check_sources("${XAMARIN_TRACING_SOURCES}") + +add_library( + ${LIB_NAME} + SHARED + ${XAMARIN_TRACING_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" +) + +target_include_directories( + ${LIB_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} +) + +target_compile_definitions( + ${LIB_NAME} + PRIVATE + XAMARIN_TRACING +) + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} + # Avoid the 'warning: dynamic exception specifications are deprecated' warning from libc++ headers + -Wno-deprecated-dynamic-exception-spec + # Prevent genration of the .eh_frame section (we don't use exceptions and don't need it) + -fno-asynchronous-unwind-tables +) + +target_link_directories( + ${LIB_NAME} + PRIVATE + ${NET_RUNTIME_DIR}/native +) + +target_link_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} +) + +target_link_libraries( + ${LIB_NAME} + PRIVATE + xa::shared-no-abi + xa::unwind + xa::runtime-base + xa::java-interop + -lmonosgen-2.0 + -llog + ${CMAKE_SYSROOT}/usr/lib/${SYSROOT_ABI_LIB_DIR}/${TOOLCHAIN_TRIPLE}/libc++abi.a +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native/tracing/native-tracing.cc b/src/native/tracing/native-tracing.cc new file mode 100644 index 00000000000..f76983a3ef1 --- /dev/null +++ b/src/native/tracing/native-tracing.cc @@ -0,0 +1,336 @@ +#include +#include +#include + +#include +#include + +#include + +#include "native-tracing.hh" +#include "shared-constants.hh" +#include "cppcompat.hh" + +constexpr int PRIORITY = ANDROID_LOG_INFO; + +static void append_frame_number (std::string &trace, size_t count) noexcept; +static unw_word_t adjust_address (unw_word_t addr) noexcept; +static void init_jni (JNIEnv *env) noexcept; + +// java.lang.Thread +static jclass java_lang_Thread; +static jmethodID java_lang_Thread_currentThread; +static jmethodID java_lang_Thread_getStackTrace; + +// java.lang.StackTraceElement +static jclass java_lang_StackTraceElement; +static jmethodID java_lang_StackTraceElement_toString; + +static std::mutex java_init_lock; + +const char* xa_get_managed_backtrace () noexcept +{ + std::string trace { "TODO: implement" }; + + return strdup (trace.c_str ()); +} + +const char* xa_get_native_backtrace () noexcept +{ + constexpr int FRAME_OFFSET_WIDTH = sizeof(uintptr_t) * 2; + + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip; + unw_word_t offp; + std::array name_buf; + std::array num_buf; // Enough for text representation of a decimal 64-bit integer + some possible + // additions (sign, padding, punctuation etc) + const char *symbol_name; + Dl_info info; + + unw_getcontext (&uc); + unw_init_local (&cursor, &uc); + + size_t frame_counter = 0; + + std::string trace; + while (unw_step (&cursor) > 0) { + if (!trace.empty ()) { + trace.append ("\n"); + } + + unw_get_reg (&cursor, UNW_REG_IP, &ip); + ip = adjust_address (ip); + + auto ptr = reinterpret_cast(ip); + const char *fname = nullptr; + const void *symptr = nullptr; + unw_word_t frame_offset = 0; + bool info_valid = false; + + if (dladdr (ptr, &info) != 0) { + if (info.dli_fname != nullptr) { + fname = info.dli_fname; + } + symptr = info.dli_sname; + frame_offset = ip - reinterpret_cast(info.dli_fbase); + info_valid = true; + } else { + frame_offset = ip; + } + + append_frame_number (trace, frame_counter++); + + std::snprintf (num_buf.data (), num_buf.size (), "%0*zx (", FRAME_OFFSET_WIDTH, frame_offset); + trace.append (num_buf.data ()); + std::snprintf (num_buf.data (), num_buf.size (), "%p) ", ptr); + trace.append (num_buf.data ()); + + // TODO: consider searching /proc/self/maps for the beginning of the corresponding region to calculate the + // correct offset (like done in bionic stack trace) + trace.append (fname != nullptr ? fname : "[anonymous]"); + + bool symbol_name_allocated = false; + offp = 0; + if (unw_get_proc_name (&cursor, name_buf.data (), name_buf.size (), &offp) == 0) { + symbol_name = name_buf.data (); + } else if (info_valid && info.dli_sname != nullptr) { + symbol_name = info.dli_sname; + } else { + symbol_name = nullptr; + } + offp = adjust_address (offp); + + if (symbol_name != nullptr) { + char *demangled_symbol_name; + int demangle_status; + + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#demangler + demangled_symbol_name = abi::__cxa_demangle (symbol_name, nullptr, nullptr, &demangle_status); + symbol_name_allocated = demangle_status == 0 && demangled_symbol_name != nullptr; + if (symbol_name_allocated) { + symbol_name = demangled_symbol_name; + } + } + + if (symbol_name != nullptr) { + trace.append (" "); + trace.append (symbol_name); + if (offp != 0) { + trace.append (" + "); + std::snprintf (num_buf.data (), num_buf.size (), "%zu", offp); + trace.append (num_buf.data ()); + } + } + + if (symptr != nullptr) { + trace.append (" (symaddr: "); + std::snprintf (num_buf.data (), num_buf.size (), "%p", symptr); + trace.append (num_buf.data ()); + trace.append (")"); + } + + if (symbol_name_allocated && symbol_name != nullptr) { + std::free (reinterpret_cast(const_cast(symbol_name))); + } + } + + return strdup (trace.c_str ()); +} + +const char* xa_get_java_backtrace (JNIEnv *env) noexcept +{ + init_jni (env); + + // TODO: error handling + jobject current_thread = env->CallStaticObjectMethod (java_lang_Thread, java_lang_Thread_currentThread); + auto stack_trace_array = static_cast(env->CallNonvirtualObjectMethod (current_thread, java_lang_Thread, java_lang_Thread_getStackTrace)); + jsize nframes = env->GetArrayLength (stack_trace_array); + std::string trace; + + for (jsize i = 0; i < nframes; i++) { + jobject frame = env->GetObjectArrayElement (stack_trace_array, i); + auto frame_desc_java = static_cast(env->CallObjectMethod (frame, java_lang_StackTraceElement_toString)); + const char *frame_desc = env->GetStringUTFChars (frame_desc_java, nullptr); + + if (!trace.empty ()) { + trace.append ("\n"); + } + + append_frame_number (trace, static_cast(i)); + trace.append (frame_desc); + env->ReleaseStringUTFChars (frame_desc_java, frame_desc); + } + + return strdup (trace.c_str ()); +} + +[[gnu::always_inline]] +unw_word_t adjust_address (unw_word_t addr) noexcept +{ + // This is what bionic does, let's do the same so that our backtrace addresses match bionic output + // Code copied verbatim from + // https://android.googlesource.com/platform/bionic/+/refs/tags/android-13.0.0_r37/libc/bionic/execinfo.cpp#50 + if (addr != 0) { +#if defined (__arm__) + // If the address is suspiciously low, do nothing to avoid a segfault trying + // to access this memory. + if (addr >= 4096) { + // Check bits [15:11] of the first halfword assuming the instruction + // is 32 bits long. If the bits are any of these values, then our + // assumption was correct: + // b11101 + // b11110 + // b11111 + // Otherwise, this is a 16 bit instruction. + uint16_t value = (*reinterpret_cast(addr - 2)) >> 11; + if (value == 0x1f || value == 0x1e || value == 0x1d) { + return addr - 4; + } + + return addr - 2; + } +#elif defined (__aarch64__) + // All instructions are 4 bytes long, skip back one instruction. + return addr - 4; +#elif defined (__i386__) || defined (__x86_64__) + // It's difficult to decode exactly where the previous instruction is, + // so subtract 1 to estimate where the instruction lives. + return addr - 1; +#endif + } + + return addr; +} + +const char* xa_get_interesting_signal_handlers () noexcept +{ + constexpr char SA_SIGNAL[] = "signal"; + constexpr char SA_SIGACTION[] = "sigaction"; + constexpr char SIG_IGNORED[] = "[ignored]"; + + std::array num_buf; + Dl_info info; + struct sigaction cur_sa; + std::string trace; + + for (int i = 0; i < _NSIG; i++) { + if (sigaction (i, nullptr, &cur_sa) != 0) { + continue; // ignore + } + + void *handler; + const char *installed_with; + if (cur_sa.sa_flags & SA_SIGINFO) { + handler = reinterpret_cast(cur_sa.sa_sigaction); + installed_with = SA_SIGACTION; + } else { + handler = reinterpret_cast(cur_sa.sa_handler); + installed_with = SA_SIGNAL; + } + + if (handler == SIG_DFL) { + continue; + } + + if (!trace.empty ()) { + trace.append ("\n"); + } + + const char *symbol_name = nullptr; + const char *file_name = nullptr; + if (handler == SIG_IGN) { + symbol_name = SIG_IGNORED; + } else { + if (dladdr (handler, &info) != 0) { + symbol_name = info.dli_sname; + file_name = info.dli_fname; + } + } + + trace.append (" "); + trace.append (strsignal (i)); + trace.append (" ("); + std::snprintf (num_buf.data (), num_buf.size (), "%d", i); + trace.append (num_buf.data ()); + trace.append ("), with "); + trace.append (installed_with); + trace.append (": "); + + if (file_name != nullptr) { + trace.append (file_name); + trace.append (" "); + } + + if (symbol_name == nullptr) { + std::snprintf (num_buf.data (), num_buf.size (), "%p", handler); + trace.append (num_buf.data ()); + } else { + trace.append (symbol_name); + } + } + + return strdup (trace.c_str ()); +} + +[[gnu::always_inline]] +void append_frame_number (std::string &trace, size_t count) noexcept +{ + std::array num_buf; // Enough for text representation of a decimal 64-bit integer + some possible + // additions (sign, padding, punctuation etc) + trace.append (" #"); + std::snprintf (num_buf.data (), num_buf.size (), "%-3zu: ", count); + trace.append (num_buf.data ()); +} + +void init_jni (JNIEnv *env) noexcept +{ + // We might be called more than once, ignore all but the first call + if (java_lang_Thread != nullptr) { + return; + } + + std::lock_guard lock (java_init_lock); + + java_lang_Thread = to_gref (env, env->FindClass ("java/lang/Thread")); + java_lang_Thread_currentThread = env->GetStaticMethodID (java_lang_Thread, "currentThread", "()Ljava/lang/Thread;"); + java_lang_Thread_getStackTrace = env->GetMethodID (java_lang_Thread, "getStackTrace", "()[Ljava/lang/StackTraceElement;"); + java_lang_StackTraceElement = to_gref (env, env->FindClass ("java/lang/StackTraceElement")); + java_lang_StackTraceElement_toString = env->GetMethodID (java_lang_StackTraceElement, "toString", "()Ljava/lang/String;"); + + // We check for the Java exception and possible null pointers only here, since all the calls JNI before the last one + // would do the exception check for us. + if (env->ExceptionOccurred ()) { + env->ExceptionDescribe (); + env->ExceptionClear (); + xamarin::android::Helpers::abort_application (); + } + + bool all_found = assert_valid_jni_pointer (java_lang_Thread, "class", "java.lang.Thread"); + all_found &= assert_valid_jni_pointer (java_lang_Thread_currentThread, "method", "java.lang.Thread.currentThread ()"); + all_found &= assert_valid_jni_pointer (java_lang_Thread_getStackTrace, "method", "java.lang.Thread.getStackTrace ()"); + all_found &= assert_valid_jni_pointer (java_lang_Thread, "class", "java.lang.StackTraceElement"); + all_found &= assert_valid_jni_pointer (java_lang_Thread_currentThread, "method", "java.lang.StackTraceElement.toString ()"); + + if (!all_found) { + xamarin::android::Helpers::abort_application (); + } +} + +bool assert_valid_jni_pointer (void *o, const char *missing_kind, const char *missing_name) noexcept +{ + if (o != nullptr) { + return true; + } + + __android_log_print ( + PRIORITY, + xamarin::android::internal::SharedConstants::LOG_CATEGORY_NAME_MONODROID_ASSEMBLY.data (), + "missing Java %s: %s", + missing_kind, + missing_name + ); + + return false; +} diff --git a/src/native/tracing/native-tracing.hh b/src/native/tracing/native-tracing.hh new file mode 100644 index 00000000000..f10697ae666 --- /dev/null +++ b/src/native/tracing/native-tracing.hh @@ -0,0 +1,48 @@ +#if !defined (__NATIVE_TRACING_HH) +#define __NATIVE_TRACING_HH + +#include +#include +#include + +#if !defined(UNW_LOCAL_ONLY) +#define UNW_LOCAL_ONLY +#endif +#include + +// Public API must not expose any types that are part of libc++ - we don't know what version of the +// library (if any) is used by the application we're embedded in. +// +// For the same reason, we cannot return memory allocated with the `new` operator - the implementation +// used by the application's C++ code might be incompatible. For this reason, any dynamically allocated +// memory we return to the caller is allocated with the libc's `malloc` +// +extern "C" { + [[gnu::visibility("default")]] + const char* xa_get_native_backtrace () noexcept; + + [[gnu::visibility("default")]] + const char* xa_get_java_backtrace (JNIEnv *env) noexcept; + + [[gnu::visibility("default")]] + const char* xa_get_managed_backtrace () noexcept; + + [[gnu::visibility("default")]] + const char* xa_get_interesting_signal_handlers () noexcept; +} + +template +[[gnu::always_inline]] +inline TJavaPointer to_gref (JNIEnv *env, TJavaPointer lref) noexcept +{ + if (lref == nullptr) { + return nullptr; + } + + auto ret = static_cast (env->NewGlobalRef (lref)); + env->DeleteLocalRef (lref); + return ret; +} + +bool assert_valid_jni_pointer (void *o, const char *missing_kind, const char *missing_name) noexcept; +#endif // ndef __NATIVE_TRACING_HH diff --git a/src/native/xamarin-app-stub/CMakeLists.txt b/src/native/xamarin-app-stub/CMakeLists.txt new file mode 100644 index 00000000000..13044940b7a --- /dev/null +++ b/src/native/xamarin-app-stub/CMakeLists.txt @@ -0,0 +1,61 @@ +set(LIB_NAME xamarin-app) +set(LIB_ALIAS xa::xamarin-app) + +set(XAMARIN_APP_SOURCES + application_dso_stub.cc +) + +add_library( + ${LIB_NAME} + SHARED + ${XAMARIN_APP_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +set(XAMARIN_APP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" +) + +target_include_directories( + ${LIB_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} +) + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} +) + +target_link_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} +) + +target_link_libraries( + ${LIB_NAME} + PRIVATE + ${SHARED_LIB_NAME} +) + +if(DEBUG_BUILD) + set(LIB_SUBDIR "Debug") +else() + set(LIB_SUBDIR "Release") +endif() + +set_target_properties( + ${LIB_NAME} + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIB_SUBDIR}" +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/monodroid/jni/application_dso_stub.cc b/src/native/xamarin-app-stub/application_dso_stub.cc similarity index 100% rename from src/monodroid/jni/application_dso_stub.cc rename to src/native/xamarin-app-stub/application_dso_stub.cc diff --git a/src/monodroid/jni/xamarin-app.hh b/src/native/xamarin-app-stub/xamarin-app.hh similarity index 99% rename from src/monodroid/jni/xamarin-app.hh rename to src/native/xamarin-app-stub/xamarin-app.hh index 7d454880faf..09301170515 100644 --- a/src/monodroid/jni/xamarin-app.hh +++ b/src/native/xamarin-app-stub/xamarin-app.hh @@ -7,8 +7,8 @@ #include #include +#include -#include "monodroid.h" #include "xxhash.hh" static constexpr uint64_t FORMAT_TAG = 0x00025E6972616D58; // 'Xmari^XY' where XY is the format version diff --git a/src/native/xamarin-debug-app-helper/CMakeLists.txt b/src/native/xamarin-debug-app-helper/CMakeLists.txt new file mode 100644 index 00000000000..1bda5881907 --- /dev/null +++ b/src/native/xamarin-debug-app-helper/CMakeLists.txt @@ -0,0 +1,60 @@ +set(LIB_NAME xamarin-debug-app-helper) +set(LIB_ALIAS xa::debug-app-helper) + +set(XAMARIN_DEBUG_HELPER_SOURCES + debug-app-helper.cc +) +add_clang_check_sources("${XAMARIN_DEBUG_HELPER_SOURCES}") + +add_library( + ${LIB_NAME} + SHARED + ${XAMARIN_DEBUG_HELPER_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +target_include_directories( + ${LIB_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} +) + +target_compile_definitions( + ${LIB_NAME} + PRIVATE -DDEBUG_APP_HELPER +) + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} +) + +target_link_directories( + ${LIB_NAME} + PRIVATE + ${NET_RUNTIME_DIR}/native +) + +target_link_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} +) + +target_link_libraries( + ${LIB_NAME} + PRIVATE + ${SHARED_LIB_NAME} + xa::xamarin-app + xa::runtime-base + xa::java-interop + -ldl + -llog + -lmonosgen-2.0 +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/monodroid/jni/debug-app-helper.cc b/src/native/xamarin-debug-app-helper/debug-app-helper.cc similarity index 73% rename from src/monodroid/jni/debug-app-helper.cc rename to src/native/xamarin-debug-app-helper/debug-app-helper.cc index eb7066b6e62..9bdffa46b76 100644 --- a/src/monodroid/jni/debug-app-helper.cc +++ b/src/native/xamarin-debug-app-helper/debug-app-helper.cc @@ -9,8 +9,8 @@ #include -#include "basic-android-system.hh" -#include "basic-utilities.hh" +#include "android-system.hh" +#include "util.hh" #include "debug-app-helper.hh" #include "shared-constants.hh" #include "jni-wrappers.hh" @@ -40,8 +40,6 @@ bool maybe_load_library (const char *path); static constexpr char TAG[] = "debug-app-helper"; unsigned int log_categories = LOG_DEFAULT | LOG_ASSEMBLY; -BasicUtilities utils; -BasicAndroidSystem androidSystem; JNIEXPORT jint JNICALL JNI_OnLoad ([[maybe_unused]] JavaVM *vm, [[maybe_unused]] void *reserved) @@ -56,17 +54,17 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, jstring_array_wrapper applicationDirs (env, appDirs); jstring_array_wrapper runtimeApks (env, runtimeApksJava); - androidSystem.detect_embedded_dso_mode (applicationDirs); - androidSystem.set_primary_override_dir (applicationDirs [0]); - androidSystem.set_override_dir (0, androidSystem.get_primary_override_dir ()); - androidSystem.setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); + AndroidSystem::detect_embedded_dso_mode (applicationDirs); + AndroidSystem::set_primary_override_dir (applicationDirs [0]); + AndroidSystem::set_override_dir (0, AndroidSystem::get_primary_override_dir ()); + AndroidSystem::setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); jstring_wrapper jstr (env); if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; - androidSystem.set_runtime_libdir (utils.strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, "Using runtime path: %s", androidSystem.get_runtime_libdir ()); + AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); + log_warn (LOG_DEFAULT, "Using runtime path: %s", AndroidSystem::get_runtime_libdir ()); } const char *monosgen_path = get_libmonosgen_path (); @@ -80,17 +78,17 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, static void copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) { - char *from_file = utils.path_combine (from_dir, file); + char *from_file = Util::path_combine (from_dir, file); char *to_file = nullptr; do { - if (!from_file || !utils.file_exists (from_file)) + if (!from_file || !Util::file_exists (from_file)) break; log_warn (LOG_DEFAULT, "Copying file `%s` from external location `%s` to internal location `%s`", file, from_dir, to_dir); - to_file = utils.path_combine (to_dir, file); + to_file = Util::path_combine (to_dir, file); if (!to_file) break; @@ -100,12 +98,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) break; } - if (!utils.file_copy (to_file, from_file)) { + if (!Util::file_copy (to_file, from_file)) { log_warn (LOG_DEFAULT, "Copy failed from `%s` to `%s`: %s", from_file, to_file, strerror (errno)); break; } - utils.set_user_executable (to_file); + Util::set_user_executable (to_file); } while (0); delete[] from_file; @@ -115,14 +113,14 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) static void copy_native_libraries_to_internal_location () { - for (const char *od : BasicAndroidSystem::override_dirs) { + for (const char *od : AndroidSystem::override_dirs) { DIR *dir; dirent *e; - char *dir_path = utils.path_combine (od, "lib"); + char *dir_path = Util::path_combine (od, "lib"); log_warn (LOG_DEFAULT, "checking directory: `%s`", dir_path); - if (dir_path == nullptr || !utils.directory_exists (dir_path)) { + if (dir_path == nullptr || !Util::directory_exists (dir_path)) { log_warn (LOG_DEFAULT, "directory does not exist: `%s`", dir_path); delete[] dir_path; continue; @@ -136,8 +134,8 @@ copy_native_libraries_to_internal_location () while ((e = readdir (dir)) != nullptr) { log_warn (LOG_DEFAULT, "checking file: `%s`", e->d_name); - if (utils.monodroid_dirent_hasextension (e, ".so")) { - copy_file_to_internal_location (androidSystem.get_primary_override_dir (), dir_path, e->d_name); + if (Util::monodroid_dirent_hasextension (e, ".so")) { + copy_file_to_internal_location (AndroidSystem::get_primary_override_dir (), dir_path, e->d_name); } } ::closedir (dir); @@ -151,9 +149,9 @@ runtime_exists (const char *dir, char*& libmonoso) if (dir == nullptr || *dir == '\0') return false; - libmonoso = utils.path_combine (dir, SharedConstants::MONO_SGEN_SO); + libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: %s", libmonoso); - if (utils.file_exists (libmonoso)) { + if (Util::file_exists (libmonoso)) { log_info (LOG_DEFAULT, "Mono runtime found at: %s", libmonoso); return true; } @@ -173,37 +171,37 @@ get_libmonosgen_path () // storage location before loading it. copy_native_libraries_to_internal_location (); - if (androidSystem.is_embedded_dso_mode_enabled ()) { + if (AndroidSystem::is_embedded_dso_mode_enabled ()) { return SharedConstants::MONO_SGEN_SO.data (); } - for (const char *od : BasicAndroidSystem::override_dirs) { + for (const char *od : AndroidSystem::override_dirs) { if (runtime_exists (od, libmonoso)) { return libmonoso; } } - for (const char *app_lib_dir : BasicAndroidSystem::app_lib_directories) { + for (const char *app_lib_dir : AndroidSystem::app_lib_directories) { if (runtime_exists (app_lib_dir, libmonoso)) { return libmonoso; } } - if (androidSystem.get_runtime_libdir () != nullptr) { - libmonoso = utils.path_combine (androidSystem.get_runtime_libdir (), SharedConstants::MONO_SGEN_ARCH_SO); + if (AndroidSystem::get_runtime_libdir () != nullptr) { + libmonoso = Util::path_combine (AndroidSystem::get_runtime_libdir (), SharedConstants::MONO_SGEN_ARCH_SO); } else libmonoso = nullptr; - if (libmonoso != nullptr && utils.file_exists (libmonoso)) { - char* links_dir = utils.path_combine (androidSystem.get_primary_override_dir (), "links"); - char* link = utils.path_combine (links_dir, SharedConstants::MONO_SGEN_SO); - if (!utils.directory_exists (links_dir)) { - if (!utils.directory_exists (androidSystem.get_primary_override_dir ())) - utils.create_public_directory (androidSystem.get_primary_override_dir ()); - utils.create_public_directory (links_dir); + if (libmonoso != nullptr && Util::file_exists (libmonoso)) { + char* links_dir = Util::path_combine (AndroidSystem::get_primary_override_dir (), "links"); + char* link = Util::path_combine (links_dir, SharedConstants::MONO_SGEN_SO); + if (!Util::directory_exists (links_dir)) { + if (!Util::directory_exists (AndroidSystem::get_primary_override_dir ())) + Util::create_public_directory (AndroidSystem::get_primary_override_dir ()); + Util::create_public_directory (links_dir); } delete[] links_dir; - if (!utils.file_exists (link)) { + if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { log_warn (LOG_DEFAULT, "symlink exists, recreating: %s -> %s", link, libmonoso); @@ -218,21 +216,21 @@ get_libmonosgen_path () } log_warn (LOG_DEFAULT, "Trying to load sgen from: %s", libmonoso != nullptr ? libmonoso : ""); - if (libmonoso != nullptr && utils.file_exists (libmonoso)) + if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; - if (runtime_exists (BasicAndroidSystem::SYSTEM_LIB_PATH.data (), libmonoso)) + if (runtime_exists (AndroidSystem::SYSTEM_LIB_PATH.data (), libmonoso)) return libmonoso; log_fatal (LOG_DEFAULT, "Cannot find '%s'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO); - for (const char *od : BasicAndroidSystem::override_dirs) { + for (const char *od : AndroidSystem::override_dirs) { if (od == nullptr) continue; log_fatal (LOG_DEFAULT, " %s", od); } - for (const char *app_lib_dir : BasicAndroidSystem::app_lib_directories) { + for (const char *app_lib_dir : AndroidSystem::app_lib_directories) { log_fatal (LOG_DEFAULT, " %s", app_lib_dir); } diff --git a/src/monodroid/jni/debug-app-helper.hh b/src/native/xamarin-debug-app-helper/debug-app-helper.hh similarity index 100% rename from src/monodroid/jni/debug-app-helper.hh rename to src/native/xamarin-debug-app-helper/debug-app-helper.hh