From 564f130305fa44d8e14613219243bcd8b3356943 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 4 Apr 2024 13:27:12 +0200 Subject: [PATCH 01/49] Begin migration from https://github.com/xamarin/xamarin-android/pull/8800 --- .gitmodules | 4 + Configuration.props | 4 + Xamarin.Android.sln | 2 + build-tools/cmake/xa_common.cmake | 144 ++++++- build-tools/cmake/xa_macros.cmake | 3 +- build-tools/cmake/xa_preamble.cmake | 7 + build-tools/scripts/cmake-android.props | 6 + .../scripts/generate-pinvoke-tables.sh | 3 +- external/libunwind | 1 + .../Android.Runtime/RuntimeNativeMethods.cs | 15 + src/libunwind-xamarin/CMakeLists.txt | 395 ++++++++++++++++++ src/libunwind-xamarin/config.h.in | 21 + .../fixes/aarch64/Gos-linux.c | 145 +++++++ .../libunwind-xamarin.csproj | 15 + .../libunwind-xamarin.targets | 54 +++ src/monodroid/CMakeLists.txt | 212 ++++------ src/monodroid/jni/cpp-util.hh | 12 +- src/monodroid/jni/generate-pinvoke-tables.cc | 1 + src/monodroid/jni/monodroid-glue-internal.hh | 29 ++ src/monodroid/jni/monodroid-tracing.cc | 89 ++++ src/monodroid/jni/pinvoke-override-api.cc | 9 + src/monodroid/jni/pinvoke-tables.include | 4 +- src/monodroid/jni/shared-constants.hh | 13 + src/monodroid/monodroid.csproj | 5 +- src/monodroid/monodroid.targets | 18 +- src/native/CMakeLists.txt | 17 + .../jni => native/shared}/cxx-abi/string.cc | 0 .../shared}/cxx-abi/terminate.cc | 0 .../jni => native/shared}/helpers.cc | 0 .../jni => native/shared}/helpers.hh | 2 +- .../jni => native/shared}/new_delete.cc | 2 + .../jni => native/shared}/platform-compat.hh | 0 src/native/tracing/native-tracing.cc | 336 +++++++++++++++ src/native/tracing/native-tracing.hh | 46 ++ 34 files changed, 1472 insertions(+), 142 deletions(-) create mode 100644 build-tools/cmake/xa_preamble.cmake create mode 100644 build-tools/scripts/cmake-android.props create mode 160000 external/libunwind create mode 100644 src/libunwind-xamarin/CMakeLists.txt create mode 100644 src/libunwind-xamarin/config.h.in create mode 100644 src/libunwind-xamarin/fixes/aarch64/Gos-linux.c create mode 100644 src/libunwind-xamarin/libunwind-xamarin.csproj create mode 100644 src/libunwind-xamarin/libunwind-xamarin.targets create mode 100644 src/monodroid/jni/monodroid-tracing.cc create mode 100644 src/native/CMakeLists.txt rename src/{monodroid/jni => native/shared}/cxx-abi/string.cc (100%) rename src/{monodroid/jni => native/shared}/cxx-abi/terminate.cc (100%) rename src/{monodroid/jni => native/shared}/helpers.cc (100%) rename src/{monodroid/jni => native/shared}/helpers.hh (97%) rename src/{monodroid/jni => native/shared}/new_delete.cc (97%) rename src/{monodroid/jni => native/shared}/platform-compat.hh (100%) create mode 100644 src/native/tracing/native-tracing.cc create mode 100644 src/native/tracing/native-tracing.hh 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 1a467652e80..0890b5b7103 100644 --- a/Configuration.props +++ b/Configuration.props @@ -104,6 +104,8 @@ True $(MSBuildThisFileDirectory)external\opentk $(MSBuildThisFileDirectory)external\sqlite + $(MSBuildThisFileDirectory)external\libunwind + $(BootstrapOutputDirectory)\libunwind $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)src-ThirdParty\ armeabi-v7a;x86 @@ -144,6 +146,8 @@ $([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 ('$(OpenTKSourceDirectory)')) net8.0 diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index c85d197a5aa..b46ca2898aa 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -47,6 +47,8 @@ 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}") = "libunwind", "src\libunwind-xamarin\libunwind-xamarin.csproj", "{F8E4961B-C427-47F9-92D6-0BEB5B76B3D7}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "monodroid", "src\monodroid\monodroid.csproj", "{53EE4C57-1C03-405A-8243-8DA539546C88}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}" diff --git a/build-tools/cmake/xa_common.cmake b/build-tools/cmake/xa_common.cmake index d732318eb05..250473e2633 100644 --- a/build-tools/cmake/xa_common.cmake +++ b/build-tools/cmake/xa_common.cmake @@ -1 +1,143 @@ -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) +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() + +# +# 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() + +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(SHARED_SOURCES_DIR "${REPO_ROOT_DIR}/src/native/shared") +set(TRACING_SOURCES_DIR "${REPO_ROOT_DIR}/src/native/tracing") +# +# Include directories +# +include_directories(SYSTEM ${CMAKE_SYSROOT}/usr/include/c++/v1/) +include_directories(SYSTEM "${NET_RUNTIME_DIR}/native/include/mono-2.0") +include_directories("${JAVA_INTEROP_SRC_PATH}") +include_directories("${SHARED_SOURCES_DIR}") +include_directories("${TRACING_SOURCES_DIR}") + +# +# Compiler defines +# +add_compile_definitions(XA_VERSION="${XA_VERSION}") +add_compile_definitions(_REENTRANT) +add_compile_definitions(PLATFORM_ANDROID) + +if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + add_compile_definitions(DEBUG) +endif() + +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() + +# +# Shared sources +# +set(XA_SHARED_SOURCES + ${SHARED_SOURCES_DIR}/helpers.cc + ${SHARED_SOURCES_DIR}/new_delete.cc +) diff --git a/build-tools/cmake/xa_macros.cmake b/build-tools/cmake/xa_macros.cmake index df23bdedcd0..69759acf363 100644 --- a/build-tools/cmake/xa_macros.cmake +++ b/build-tools/cmake/xa_macros.cmake @@ -200,7 +200,8 @@ function(xa_common_prepare) -fstack-protector-strong -fstrict-return -fno-strict-aliasing - -ffunction-sections + -fno-function-sections + -fno-data-sections -funswitch-loops -Wa,-noexecstack -fPIC diff --git a/build-tools/cmake/xa_preamble.cmake b/build-tools/cmake/xa_preamble.cmake new file mode 100644 index 00000000000..d28fc5e10c4 --- /dev/null +++ b/build-tools/cmake/xa_preamble.cmake @@ -0,0 +1,7 @@ +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) + +# +# 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}") 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 e0136d126f1..a63853f8562 100755 --- a/build-tools/scripts/generate-pinvoke-tables.sh +++ b/build-tools/scripts/generate-pinvoke-tables.sh @@ -9,6 +9,7 @@ TARGET_FILE="${MONODROID_SOURCE_DIR}/pinvoke-tables.include" GENERATED_FILE="${TARGET_FILE}.generated" DIFF_FILE="${TARGET_FILE}.diff" EXTERNAL_DIR="${MY_DIR}/../../external/" +NATIVE_DIR="${MY_DIR}/../../src/native" function die() { @@ -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/external/libunwind b/external/libunwind new file mode 160000 index 00000000000..3705baed4dd --- /dev/null +++ b/external/libunwind @@ -0,0 +1 @@ +Subproject commit 3705baed4ddb5a98138d16dd2effcaeaa7e72db5 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/libunwind-xamarin/CMakeLists.txt b/src/libunwind-xamarin/CMakeLists.txt new file mode 100644 index 00000000000..02ad008d774 --- /dev/null +++ b/src/libunwind-xamarin/CMakeLists.txt @@ -0,0 +1,395 @@ +cmake_minimum_required(VERSION 3.19) + +# +# MUST be included before project()! +# +include("../../build-tools/cmake/xa_preamble.cmake") + +if(NOT DEFINED LIBUNWIND_LIBRARY_NAME) + message(FATAL_ERROR "Please set the LIBUNWIND_LIBRARY_NAME variable on command line (-DLIBUNWIND_LIBRARY_NAME=base_library_name)") +endif() + +if(NOT DEFINED LIBUNWIND_SOURCE_DIR) + message(FATAL_ERROR "Please set the LIBUNWIND_SOURCE_DIR variable on command line (-DLIBUNWIND_SOURCE_DIR=source_dir_path)") +endif() + +if(NOT DEFINED LIBUNWIND_OUTPUT_DIR) + message(FATAL_ERROR "Please set the LIBUNWIND_OUTPUT_DIR variable on command line (-DLIBUNWIND_OUTPUT_DIR=output_dir_path)") +endif() + +if(NOT DEFINED LIBUNWIND_HEADERS_OUTPUT_DIR) + message(FATAL_ERROR "Please set the LIBUNWIND_HEADERS_OUTPUT_DIR variable on command line (-DLIBUNWIND_HEADERS_OUTPUT_DIR=output_dir_path)") +endif() + +# +# 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 "Major: ${PKG_MAJOR}; Minor: ${PKG_MINOR}; Extra: ${PKG_EXTRA}") + +project( + libunwind-xamarin +# VERSION "${PKG_MAJOR}.${PKG_MINOR}.${PKG_EXTRA}" + LANGUAGES C ASM +) + +# +# MUST be included after project()! +# +include("../../build-tools/cmake/xa_common.cmake") + +include(CheckCSourceCompiles) +include(CheckIncludeFiles) +include(CheckSymbolExists) +include("../../build-tools/cmake/xa_macros.cmake") + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_OUTPUT_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_OUTPUT_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_OUTPUT_DIR}) + +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() + +set(DSO_SYMBOL_VISIBILITY "hidden") +xa_common_prepare() + +if(CMAKE_BUILD_TYPE STREQUAL Debug) + list(APPEND LOCAL_COMPILER_ARGS -g -fno-omit-frame-pointer) +else() + list(APPEND LOCAL_COMPILER_ARGS -s -fomit-frame-pointer) + add_compile_definitions(NDEBUG) +endif() +list(APPEND LOCAL_COMPILER_ARGS + ${XA_DEFAULT_SYMBOL_VISIBILITY} + -fno-asynchronous-unwind-tables + -fno-unwind-tables +) + +xa_check_c_flags(XA_C_FLAGS "${LOCAL_COMPILER_ARGS}") +xa_check_c_linker_flags(XA_C_LINKER_FLAGS "${LOCAL_COMPILER_ARGS}") + +add_compile_options(${XA_C_FLAGS}) +add_link_options(${XA_C_LINKER_FLAGS}) + +add_compile_definitions(HAVE_CONFIG_H) +add_compile_definitions(_GNU_SOURCE) +add_compile_definitions(UNW_LOCAL_ONLY) # we don't need remote unwinding + +# 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) + +# The files are nearly identical, the only difference is name of the header included when remote-only libunwind is used +# We don't use it, but we still copy files to separate directories in order to avoid locking issues during parallel builds +set(HEADERS_DIR ${LIBUNWIND_HEADERS_OUTPUT_DIR}/${CMAKE_ANDROID_ARCH_ABI}) + +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind-common.h DESTINATION ${HEADERS_DIR}) +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind.h DESTINATION ${HEADERS_DIR}) +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/include/tdep/libunwind_i.h DESTINATION ${HEADERS_DIR}/tdep/) + +include_directories(${LIBUNWIND_SOURCE_DIR}/include/tdep) +include_directories(${LIBUNWIND_SOURCE_DIR}/include) +include_directories(${LIBUNWIND_SOURCE_DIR}/src) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/tdep) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) + +if(TARGET_ARM) + # Ensure that the remote and local unwind code can reside in the same binary without name clashing + add_definitions("-Darm_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 + include_directories(${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() + +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(${LIBUNWIND_LIBRARY_NAME} + STATIC + ${LIBUNWIND_XAMARIN_SOURCES} +) + +target_link_options( + ${LIBUNWIND_LIBRARY_NAME} + PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} +) diff --git a/src/libunwind-xamarin/config.h.in b/src/libunwind-xamarin/config.h.in new file mode 100644 index 00000000000..52656bb9740 --- /dev/null +++ b/src/libunwind-xamarin/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/libunwind-xamarin/fixes/aarch64/Gos-linux.c b/src/libunwind-xamarin/fixes/aarch64/Gos-linux.c new file mode 100644 index 00000000000..fd9f266427c --- /dev/null +++ b/src/libunwind-xamarin/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/libunwind-xamarin/libunwind-xamarin.csproj b/src/libunwind-xamarin/libunwind-xamarin.csproj new file mode 100644 index 00000000000..b7aba4a3cfb --- /dev/null +++ b/src/libunwind-xamarin/libunwind-xamarin.csproj @@ -0,0 +1,15 @@ + + + Exe + netstandard2.0 + False + + + + + + $(MicrosoftAndroidSdkOutDir)lib + + + + diff --git a/src/libunwind-xamarin/libunwind-xamarin.targets b/src/libunwind-xamarin/libunwind-xamarin.targets new file mode 100644 index 00000000000..3b989aec4aa --- /dev/null +++ b/src/libunwind-xamarin/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/monodroid/CMakeLists.txt b/src/monodroid/CMakeLists.txt index 469a4ef5fca..a82cddea564 100644 --- a/src/monodroid/CMakeLists.txt +++ b/src/monodroid/CMakeLists.txt @@ -1,15 +1,9 @@ -cmake_minimum_required(VERSION 3.18.1) +cmake_minimum_required(VERSION 3.19) # # 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}") +include("../../build-tools/cmake/xa_preamble.cmake") project( monodroid @@ -17,76 +11,14 @@ project( DESCRIPTION "Xamarin.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() +# +# MUST be included after project()! +# +include("../../build-tools/cmake/xa_common.cmake") 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 @@ -112,53 +44,30 @@ 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() +if(NOT DEFINED LIBUNWIND_SOURCE_DIR) + message(FATAL_ERROR "Please set the LIBUNWIND_SOURCE_DIR on command line (-DLIBUNWIND_SOURCE_DIR=path)") +endif() + +if(NOT DEFINED LIBUNWIND_HEADERS_DIR) + message(FATAL_ERROR "Please set the LIBUNWIND_HEADERS_DIR on command line (-DLIBUNWIND_HEADERS_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(BIONIC_SOURCES_DIR "${REPO_ROOT_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(XA_BIN_DIR "${REPO_ROOT_DIR}/bin/${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" ) @@ -171,9 +80,8 @@ include_directories(${EXTERNAL_DIR}) # 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") @@ -182,7 +90,6 @@ include_directories("${XA_BIN_DIR}/include/${ANDROID_ABI}/eglib") 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") @@ -192,10 +99,8 @@ 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) @@ -214,15 +119,6 @@ if (ENABLE_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 @@ -376,6 +272,7 @@ endif() 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) +set(XAMARIN_NATIVE_TRACING_LIB xamarin-native-tracing) string(TOLOWER ${CMAKE_BUILD_TYPE} XAMARIN_MONO_ANDROID_SUFFIX) set(XAMARIN_MONO_ANDROID_LIB "mono-android${CHECKED_BUILD_INFIX}.${XAMARIN_MONO_ANDROID_SUFFIX}") @@ -387,6 +284,7 @@ set(XAMARIN_MONODROID_SOURCES ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc ${JAVA_INTEROP_SRC_PATH}/java-interop.cc ${LZ4_SOURCES} + ${XA_SHARED_SOURCES} ${SOURCES_DIR}/android-system.cc ${SOURCES_DIR}/basic-android-system.cc ${SOURCES_DIR}/basic-utilities.cc @@ -396,14 +294,13 @@ set(XAMARIN_MONODROID_SOURCES ${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}/monodroid-tracing.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 @@ -422,11 +319,18 @@ 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 + ${SHARED_SOURCES_DIR}/cxx-abi/string.cc + ${SHARED_SOURCES_DIR}/cxx-abi/terminate.cc ) endif() +set(NATIVE_TRACING_SOURCES + ${SHARED_SOURCES_DIR}/cxx-abi/string.cc +# ${SHARED_SOURCES_DIR}/cxx-abi/terminate.cc + ${TRACING_SOURCES_DIR}/native-tracing.cc + ${XA_SHARED_SOURCES} +) + set(XAMARIN_APP_STUB_SOURCES ${SOURCES_DIR}/application_dso_stub.cc ) @@ -436,9 +340,8 @@ set(XAMARIN_DEBUG_APP_HELPER_SOURCES ${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 + ${XA_SHARED_SOURCES} ) set(XAMARIN_STUB_LIB_SOURCES @@ -503,6 +406,52 @@ add_library( SHARED ${XAMARIN_MONODROID_SOURCES} ) +if(NOT DEBUG_BUILD) + set(CPP_ABI_PATH ${CMAKE_SYSROOT}/usr/lib/${SYSROOT_ABI_LIB_DIR}/${TOOLCHAIN_TRIPLE}/libc++abi.a) + + add_library( + ${XAMARIN_NATIVE_TRACING_LIB} + SHARED ${NATIVE_TRACING_SOURCES} + ) + + target_include_directories( + ${XAMARIN_NATIVE_TRACING_LIB} BEFORE + PRIVATE + ${LIBUNWIND_SOURCE_DIR}/include + ${LIBUNWIND_HEADERS_DIR}/${CMAKE_ANDROID_ARCH_ABI} + ${NDK_CXX_LIBCPPABI_SOURCE_PATH}/include + ) + + target_compile_options( + ${XAMARIN_NATIVE_TRACING_LIB} + PRIVATE + # Avoid the 'warning: dynamic exception specifications are deprecated' warning from libc++ headers + -Wno-deprecated-dynamic-exception-spec + ${XA_DEFAULT_SYMBOL_VISIBILITY} + # Prevent genration of the .eh_frame section (we don't use exceptions and don't need it) + -fno-asynchronous-unwind-tables + ) + + target_link_options( + ${XAMARIN_NATIVE_TRACING_LIB} + PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} + ) + + target_link_libraries( + ${XAMARIN_NATIVE_TRACING_LIB} + PRIVATE + -llog + ${CPP_ABI_PATH} + ${XA_LIBRARY_OUTPUT_DIRECTORY}/libunwind_xamarin.a + ) + + target_compile_definitions( + ${XAMARIN_NATIVE_TRACING_LIB} + PRIVATE + XAMARIN_TRACING + ) +endif() + # 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\")))") @@ -511,6 +460,13 @@ target_compile_options( PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} "${LZ4_VISIBILITY_OPTS}" ) +target_include_directories( + ${XAMARIN_MONO_ANDROID_LIB} BEFORE + PRIVATE + ${LIBUNWIND_SOURCE_DIR}/include + ${LIBUNWIND_HEADERS_DIR}/${CMAKE_ANDROID_ARCH_ABI} +) + set(DEBUG_HELPER_LINK_LIBS "-ldl") target_link_options( diff --git a/src/monodroid/jni/cpp-util.hh b/src/monodroid/jni/cpp-util.hh index 8f50149eb33..66dddc1d325 100644 --- a/src/monodroid/jni/cpp-util.hh +++ b/src/monodroid/jni/cpp-util.hh @@ -43,9 +43,19 @@ 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/generate-pinvoke-tables.cc b/src/monodroid/jni/generate-pinvoke-tables.cc index bcc9bce2acf..c29358d1e5b 100644 --- a/src/monodroid/jni/generate-pinvoke-tables.cc +++ b/src/monodroid/jni/generate-pinvoke-tables.cc @@ -61,6 +61,7 @@ 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", diff --git a/src/monodroid/jni/monodroid-glue-internal.hh b/src/monodroid/jni/monodroid-glue-internal.hh index abd3401671c..a8245495dd4 100644 --- a/src/monodroid/jni/monodroid-glue-internal.hh +++ b/src/monodroid/jni/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-tracing.cc b/src/monodroid/jni/monodroid-tracing.cc new file mode 100644 index 00000000000..7f85117ae27 --- /dev/null +++ b/src/monodroid/jni/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 "cppcompat.hh" +#include + +using namespace xamarin::android::internal; + +static decltype(xa_get_native_backtrace)* _xa_get_native_backtrace; +static decltype(xa_get_managed_backtrace)* _xa_get_managed_backtrace; +static decltype(xa_get_java_backtrace)* _xa_get_java_backtrace; +static decltype(xa_get_interesting_signal_handlers)* _xa_get_interesting_signal_handlers; +static bool tracing_init_done; + +static 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/pinvoke-override-api.cc b/src/monodroid/jni/pinvoke-override-api.cc index 94232f60045..09710484807 100644 --- a/src/monodroid/jni/pinvoke-override-api.cc +++ b/src/monodroid/jni/pinvoke-override-api.cc @@ -363,6 +363,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/monodroid/jni/pinvoke-tables.include index 1f3c479095c..e358a4d848f 100644 --- a/src/monodroid/jni/pinvoke-tables.include +++ b/src/monodroid/jni/pinvoke-tables.include @@ -18,6 +18,7 @@ static PinvokeEntry internal_pinvokes[] = { {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)}, @@ -540,6 +541,7 @@ static PinvokeEntry internal_pinvokes[] = { {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)}, @@ -989,5 +991,5 @@ constexpr hash_t system_io_compression_native_library_hash = 0xafe3142c; constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93625cd; #endif -constexpr size_t internal_pinvokes_count = 49; +constexpr size_t internal_pinvokes_count = 50; constexpr size_t dotnet_pinvokes_count = 428; diff --git a/src/monodroid/jni/shared-constants.hh b/src/monodroid/jni/shared-constants.hh index 2c706ae2df7..1ecdbcf90e5 100644 --- a/src/monodroid/jni/shared-constants.hh +++ b/src/monodroid/jni/shared-constants.hh @@ -83,6 +83,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/monodroid.csproj b/src/monodroid/monodroid.csproj index c4dbc2d7b5c..100496fe8fc 100644 --- a/src/monodroid/monodroid.csproj +++ b/src/monodroid/monodroid.csproj @@ -6,7 +6,7 @@ Exe false - + @@ -14,8 +14,9 @@ - + + diff --git a/src/monodroid/monodroid.targets b/src/monodroid/monodroid.targets index ed667e7fc44..7d0c3010bbf 100644 --- a/src/monodroid/monodroid.targets +++ b/src/monodroid/monodroid.targets @@ -1,6 +1,7 @@ + @@ -74,43 +75,48 @@ DependsOnTargets="_ConfigureRuntimesInputs" Inputs="@(_ConfigureRuntimesInputs)" Outputs="@(_ConfigureRuntimesOutputs)"> + + + + <_CmakeLibUnwind>-DLIBUNWIND_SOURCE_DIR="$(LibUnwindSourceDirectory)" -DLIBUNWIND_HEADERS_DIR="$(LibUnwindGeneratedHeadersDirectory)" <_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) + <_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)" + $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" $(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)" + $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" $(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)" + $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" $(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)" + $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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 <_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)" + $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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 <_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)" + $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt new file mode 100644 index 00000000000..b7a0a0daee3 --- /dev/null +++ b/src/native/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.19) + +# +# MUST be included before project()! +# +include("../../build-tools/cmake/xa_preamble.cmake") + +project( + native-libs + VERSION ${XA_VERSION} + LANGUAGES CXX +) + +# +# MUST be included after project()! +# +include("../../build-tools/cmake/xa_common.cmake") 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/monodroid/jni/helpers.cc b/src/native/shared/helpers.cc similarity index 100% rename from src/monodroid/jni/helpers.cc rename to src/native/shared/helpers.cc diff --git a/src/monodroid/jni/helpers.hh b/src/native/shared/helpers.hh similarity index 97% rename from src/monodroid/jni/helpers.hh rename to src/native/shared/helpers.hh index 88d4904e92d..fe5b03ecda1 100644 --- a/src/monodroid/jni/helpers.hh +++ b/src/native/shared/helpers.hh @@ -12,7 +12,7 @@ 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 + class [[gnu::visibility("hidden")]] Helpers { public: template 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/native/tracing/native-tracing.cc b/src/native/tracing/native-tracing.cc new file mode 100644 index 00000000000..5b69cda234a --- /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, 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..6f08e7273b3 --- /dev/null +++ b/src/native/tracing/native-tracing.hh @@ -0,0 +1,46 @@ +#if !defined (__NATIVE_TRACING_HH) +#define __NATIVE_TRACING_HH + +#include +#include +#include + +#define UNW_LOCAL_ONLY +#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 From 8554fed17f22ed5f8e450345a3f103bd204a107c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 5 Apr 2024 09:43:01 +0000 Subject: [PATCH 02/49] Bumps LLVM to v18.1.3 and XA utils version to 8.0.0 (#8852) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: https://discourse.llvm.org/t/llvm-18-1-0-released/77448 Changes: https://discourse.llvm.org/t/llvm-18-1-1-released/77540 Changes: https://discourse.llvm.org/t/18-1-2-released/77821 Changes: https://discourse.llvm.org/t/18-1-3-released/78136 Changes interesting for us: * AArch64 backend * Added support for Cortex-A520, Cortex-A720 and Cortex-X4 CPUs. * Assembler/disassembler support has been added for 2023 architecture extensions. * Support has been added for Stack Clash Protection. During function frame creation and dynamic stack allocations, the compiler will issue memory accesses at regular intervals so that a guard area at the top of the stack can’t be skipped over. * x86 backend * The i128 type now matches GCC and clang’s __int128 type. This mainly benefits external projects such as Rust which aim to be binary compatible with C, but also fixes code generation where LLVM already assumed that the type matched and called into libgcc helper functions. **Full Changelog**: https://github.com/xamarin/xamarin-android-binutils/compare/L_17.0.6-7.2.1...L_18.1.3-8.0.0 --- build-tools/installers/unix-binutils.projitems | 4 +++- .../xaprepare/xaprepare/ConfigAndData/Configurables.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build-tools/installers/unix-binutils.projitems b/build-tools/installers/unix-binutils.projitems index b1df3153b61..519c1daed2b 100644 --- a/build-tools/installers/unix-binutils.projitems +++ b/build-tools/installers/unix-binutils.projitems @@ -1,7 +1,7 @@ - <_LlvmLibExtension Condition=" '$(HostOS)' == 'Linux' ">so.17 + <_LlvmLibExtension Condition=" '$(HostOS)' == 'Linux' ">so.18.1 <_LlvmLibExtension Condition=" '$(HostOS)' == 'Darwin' ">dylib @@ -62,8 +62,10 @@ <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMDebugInfoPDB.$(_LlvmLibExtension)" /> <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMDemangle.$(_LlvmLibExtension)" /> <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMExtensions.$(_LlvmLibExtension)" /> + <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMFrontendOffloading.$(_LlvmLibExtension)" /> <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMFrontendOpenMP.$(_LlvmLibExtension)" /> <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMGlobalISel.$(_LlvmLibExtension)" /> + <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMHipStdPar.$(_LlvmLibExtension)" /> <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMInstCombine.$(_LlvmLibExtension)" /> <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMInstrumentation.$(_LlvmLibExtension)" /> <_BinUtilsFilesUnixSign Include="$(MicrosoftAndroidSdkOutDir)$(HostOS)\binutils\lib\libLLVMipo.$(_LlvmLibExtension)" /> diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 89c29ba32c5..cc349751b43 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -15,7 +15,7 @@ namespace Xamarin.Android.Prepare // partial class Configurables { - const string BinutilsVersion = "L_17.0.6-7.2.1"; + const string BinutilsVersion = "L_18.1.3-8.0.0"; const string MicrosoftOpenJDK17Version = "17.0.8"; const string MicrosoftOpenJDK17Release = "17.0.8.7"; From 42e199ae437e45d2539b52a04505e9425f030d81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 10:54:31 -1000 Subject: [PATCH 03/49] Bump external/Java.Interop from `651de42` to `e1c7832` (#8836) Bumps [external/Java.Interop](https://github.com/xamarin/java.interop) from `651de42` to `e1c7832`. - [Commits](https://github.com/xamarin/java.interop/compare/651de42732d194cee5a45fae45feda37706a8c16...e1c78326fbe2679cd90854c15d31f0fba7b796b6) --- updated-dependencies: - dependency-name: external/Java.Interop dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- external/Java.Interop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/Java.Interop b/external/Java.Interop index 651de42732d..e1c78326fbe 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit 651de42732d194cee5a45fae45feda37706a8c16 +Subproject commit e1c78326fbe2679cd90854c15d31f0fba7b796b6 From b9b057166c3b7a87ef87c018047929b7768747eb Mon Sep 17 00:00:00 2001 From: Peter Collins Date: Mon, 8 Apr 2024 23:59:06 -0700 Subject: [PATCH 04/49] [ci] Update dependabot ignore list (#8864) Updates the list of submodules that dependabot ignores when checking for updates. Repos which are no longer valid have been removed and recently added xxhash repos have been added to this list. --- .github/dependabot.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9c3f02fab8f..1661447e8ee 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,10 +14,8 @@ updates: schedule: interval: "daily" ignore: - - dependency-name: "external/apksig" + - dependency-name: "external/constexpr-xxh3" - dependency-name: "external/debugger-libs" - dependency-name: "external/lz4" - - dependency-name: "external/nrefactory" - - dependency-name: "external/opentk" - dependency-name: "external/robin-map" - - dependency-name: "external/sqlite" + - dependency-name: "external/xxHash" From 842d3c3228bcf808fbee517795a22b72b6cbfc83 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Apr 2024 16:28:23 +0200 Subject: [PATCH 05/49] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 28 +++--- .../BuildReleaseArm64XFormsDotNet.apkdesc | 90 +++++++++---------- 2 files changed, 59 insertions(+), 59 deletions(-) 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..aa48fb18d6c 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,31 +11,31 @@ "Size": 1027 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 64234 + "Size": 64238 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 91668 + "Size": 91590 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5222 + "Size": 5318 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 6548 + "Size": 6543 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 8483 + "Size": 8520 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 566421 + "Size": 566145 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 2552 + "Size": 2545 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 4025 + "Size": 4017 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 2934 + "Size": 2932 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 1512 @@ -44,10 +44,10 @@ "Size": 87352 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 354064 + "Size": 481952 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3132992 + "Size": 3135328 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 67248 @@ -62,10 +62,10 @@ "Size": 155568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 12656 + "Size": 12696 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { "Size": 3266 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 2689557 + "PackageSize": 2738709 } \ 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..979456f1439 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": 72398 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 458327 + "Size": 458239 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5222 + "Size": 5318 }, "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": 11517 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { - "Size": 15413 + "Size": 15409 }, "lib/arm64-v8a/lib_System.Collections.NonGeneric.dll.so": { - "Size": 7441 + "Size": 7436 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { - "Size": 1941 + "Size": 1934 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 2555 + "Size": 2548 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 6089 + "Size": 6082 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 6580 + "Size": 6575 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 1976 + "Size": 1968 }, "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { - "Size": 9065 + "Size": 9057 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 6552 + "Size": 6543 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 2331 + "Size": 2323 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 1937 + "Size": 1931 }, "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": 11184 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { - "Size": 15864 + "Size": 15861 }, "lib/arm64-v8a/lib_System.IO.IsolatedStorage.dll.so": { - "Size": 9897 + "Size": 9893 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 20166 + "Size": 20208 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 164751 + "Size": 164627 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 67559 + "Size": 68134 }, "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": 8561 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 872867 + "Size": 872591 }, "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": 42906 }, "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": 16624 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 2709 + "Size": 2701 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 4025 + "Size": 4017 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 1865 + "Size": 1858 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 2484 + "Size": 2478 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 3758 + "Size": 3751 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 8102 + "Size": 8095 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 161398 + "Size": 161223 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 1760 + "Size": 1753 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 1776 + "Size": 1769 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 5007 @@ -239,10 +239,10 @@ "Size": 87352 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 354064 + "Size": 481952 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3132992 + "Size": 3135328 }, "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": 10267688 } \ No newline at end of file From 9cf8516772c225f9dd1dd0a524ed2aadacf7aa8c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 11 Apr 2024 22:08:45 +0200 Subject: [PATCH 06/49] [WIP] Migration to new native sources layout Build is broken atm --- .../Microsoft.Android.Runtime.proj | 2 + src/native/CMakeLists.txt | 137 +++++++- src/native/CMakePresets.json | 309 ++++++++++++++++++ src/native/CMakeUserPresets.json | 47 +++ src/{monodroid => native}/libstub/stub.cc | 0 .../libunwind}/CMakeLists.txt | 0 .../libunwind}/config.h.in | 0 .../libunwind}/fixes/aarch64/Gos-linux.c | 0 .../libunwind}/libunwind-xamarin.csproj | 0 .../libunwind}/libunwind-xamarin.targets | 0 src/{ => native}/monodroid/.gitignore | 0 src/{ => native}/monodroid/CMakeLists.txt | 0 src/{ => native}/monodroid/config.xml | 0 src/{ => native}/monodroid/jni/.gitignore | 0 src/{ => native}/monodroid/jni/TODO.md | 0 .../monodroid/jni/android-system.cc | 0 .../monodroid/jni/android-system.hh | 0 .../monodroid/jni/application_dso_stub.cc | 0 .../monodroid/jni/basic-android-system.cc | 0 .../monodroid/jni/basic-android-system.hh | 0 .../monodroid/jni/basic-utilities.cc | 0 .../monodroid/jni/basic-utilities.hh | 0 src/{ => native}/monodroid/jni/build-info.hh | 0 src/{ => native}/monodroid/jni/config.h | 0 src/{ => native}/monodroid/jni/cpp-util.hh | 0 src/{ => native}/monodroid/jni/cppcompat.hh | 0 .../monodroid/jni/cpu-arch-detect.cc | 0 src/{ => native}/monodroid/jni/cpu-arch.hh | 0 .../monodroid/jni/debug-app-helper.cc | 0 .../monodroid/jni/debug-app-helper.hh | 0 .../monodroid/jni/debug-constants.cc | 0 src/{ => native}/monodroid/jni/debug.cc | 0 src/{ => native}/monodroid/jni/debug.hh | 0 .../monodroid/jni/designer-assemblies.cc | 0 .../monodroid/jni/designer-assemblies.hh | 0 .../monodroid/jni/embedded-assemblies-zip.cc | 0 .../monodroid/jni/embedded-assemblies.cc | 0 .../monodroid/jni/embedded-assemblies.hh | 0 .../monodroid/jni/generate-pinvoke-tables.cc | 0 src/{ => native}/monodroid/jni/globals.cc | 0 src/{ => native}/monodroid/jni/globals.hh | 0 .../monodroid/jni/host-config.h.in | 0 .../monodroid/jni/internal-pinvoke-api.cc | 0 .../monodroid/jni/jni-remapping.cc | 0 .../monodroid/jni/jni-remapping.hh | 0 .../monodroid/jni/jni-wrappers.hh | 0 src/{ => native}/monodroid/jni/logger.cc | 0 src/{ => native}/monodroid/jni/logger.hh | 0 .../monodroid/jni/mono-image-loader.hh | 0 .../monodroid/jni/mono-log-adapter.cc | 0 .../monodroid/jni/mono_android_Runtime.h | 0 .../monodroid/jni/monodroid-glue-designer.cc | 0 .../monodroid/jni/monodroid-glue-internal.hh | 0 .../monodroid/jni/monodroid-glue.cc | 0 .../monodroid/jni/monodroid-glue.hh | 0 .../monodroid/jni/monodroid-networkinfo.cc | 0 .../monodroid/jni/monodroid-tracing.cc | 0 src/{ => native}/monodroid/jni/monodroid.h | 0 src/{ => native}/monodroid/jni/monodroid.x | Bin .../monodroid/jni/monovm-properties.cc | 0 .../monodroid/jni/monovm-properties.hh | 0 src/{ => native}/monodroid/jni/osbridge.cc | 0 src/{ => native}/monodroid/jni/osbridge.hh | 0 .../monodroid/jni/pinvoke-override-api.cc | 0 .../monodroid/jni/pinvoke-tables.include | 0 src/{ => native}/monodroid/jni/search.hh | 0 .../monodroid/jni/shared-constants.cc | 0 .../monodroid/jni/shared-constants.hh | 0 .../monodroid/jni/startup-aware-lock.hh | 0 src/{ => native}/monodroid/jni/strings.hh | 0 src/{ => native}/monodroid/jni/timezones.cc | 0 .../monodroid/jni/timing-internal.cc | 0 .../monodroid/jni/timing-internal.hh | 0 src/{ => native}/monodroid/jni/timing.hh | 0 src/{ => native}/monodroid/jni/util.cc | 0 src/{ => native}/monodroid/jni/util.hh | 0 src/{ => native}/monodroid/jni/win32/jni_md.h | 0 .../monodroid/jni/xa-internal-api-impl.hh | 0 .../monodroid/jni/xa-internal-api.cc | 0 .../monodroid/jni/xa-internal-api.hh | 0 .../jni/xamarin-android-app-context.cc | 0 src/{ => native}/monodroid/jni/xamarin-app.hh | 0 .../monodroid/jni/xamarin_getifaddrs.cc | 0 .../monodroid/jni/xamarin_getifaddrs.h | 0 src/{ => native}/monodroid/jni/xxhash.hh | 0 src/{ => native}/monodroid/machine.config.xml | 0 src/{ => native}/monodroid/monodroid.csproj | 0 src/{ => native}/monodroid/monodroid.targets | 0 88 files changed, 488 insertions(+), 7 deletions(-) create mode 100644 src/native/CMakePresets.json create mode 100644 src/native/CMakeUserPresets.json rename src/{monodroid => native}/libstub/stub.cc (100%) rename src/{libunwind-xamarin => native/libunwind}/CMakeLists.txt (100%) rename src/{libunwind-xamarin => native/libunwind}/config.h.in (100%) rename src/{libunwind-xamarin => native/libunwind}/fixes/aarch64/Gos-linux.c (100%) rename src/{libunwind-xamarin => native/libunwind}/libunwind-xamarin.csproj (100%) rename src/{libunwind-xamarin => native/libunwind}/libunwind-xamarin.targets (100%) rename src/{ => native}/monodroid/.gitignore (100%) rename src/{ => native}/monodroid/CMakeLists.txt (100%) rename src/{ => native}/monodroid/config.xml (100%) rename src/{ => native}/monodroid/jni/.gitignore (100%) rename src/{ => native}/monodroid/jni/TODO.md (100%) rename src/{ => native}/monodroid/jni/android-system.cc (100%) rename src/{ => native}/monodroid/jni/android-system.hh (100%) rename src/{ => native}/monodroid/jni/application_dso_stub.cc (100%) rename src/{ => native}/monodroid/jni/basic-android-system.cc (100%) rename src/{ => native}/monodroid/jni/basic-android-system.hh (100%) rename src/{ => native}/monodroid/jni/basic-utilities.cc (100%) rename src/{ => native}/monodroid/jni/basic-utilities.hh (100%) rename src/{ => native}/monodroid/jni/build-info.hh (100%) rename src/{ => native}/monodroid/jni/config.h (100%) rename src/{ => native}/monodroid/jni/cpp-util.hh (100%) rename src/{ => native}/monodroid/jni/cppcompat.hh (100%) rename src/{ => native}/monodroid/jni/cpu-arch-detect.cc (100%) rename src/{ => native}/monodroid/jni/cpu-arch.hh (100%) rename src/{ => native}/monodroid/jni/debug-app-helper.cc (100%) rename src/{ => native}/monodroid/jni/debug-app-helper.hh (100%) rename src/{ => native}/monodroid/jni/debug-constants.cc (100%) rename src/{ => native}/monodroid/jni/debug.cc (100%) rename src/{ => native}/monodroid/jni/debug.hh (100%) rename src/{ => native}/monodroid/jni/designer-assemblies.cc (100%) rename src/{ => native}/monodroid/jni/designer-assemblies.hh (100%) rename src/{ => native}/monodroid/jni/embedded-assemblies-zip.cc (100%) rename src/{ => native}/monodroid/jni/embedded-assemblies.cc (100%) rename src/{ => native}/monodroid/jni/embedded-assemblies.hh (100%) rename src/{ => native}/monodroid/jni/generate-pinvoke-tables.cc (100%) rename src/{ => native}/monodroid/jni/globals.cc (100%) rename src/{ => native}/monodroid/jni/globals.hh (100%) rename src/{ => native}/monodroid/jni/host-config.h.in (100%) rename src/{ => native}/monodroid/jni/internal-pinvoke-api.cc (100%) rename src/{ => native}/monodroid/jni/jni-remapping.cc (100%) rename src/{ => native}/monodroid/jni/jni-remapping.hh (100%) rename src/{ => native}/monodroid/jni/jni-wrappers.hh (100%) rename src/{ => native}/monodroid/jni/logger.cc (100%) rename src/{ => native}/monodroid/jni/logger.hh (100%) rename src/{ => native}/monodroid/jni/mono-image-loader.hh (100%) rename src/{ => native}/monodroid/jni/mono-log-adapter.cc (100%) rename src/{ => native}/monodroid/jni/mono_android_Runtime.h (100%) rename src/{ => native}/monodroid/jni/monodroid-glue-designer.cc (100%) rename src/{ => native}/monodroid/jni/monodroid-glue-internal.hh (100%) rename src/{ => native}/monodroid/jni/monodroid-glue.cc (100%) rename src/{ => native}/monodroid/jni/monodroid-glue.hh (100%) rename src/{ => native}/monodroid/jni/monodroid-networkinfo.cc (100%) rename src/{ => native}/monodroid/jni/monodroid-tracing.cc (100%) rename src/{ => native}/monodroid/jni/monodroid.h (100%) rename src/{ => native}/monodroid/jni/monodroid.x (100%) rename src/{ => native}/monodroid/jni/monovm-properties.cc (100%) rename src/{ => native}/monodroid/jni/monovm-properties.hh (100%) rename src/{ => native}/monodroid/jni/osbridge.cc (100%) rename src/{ => native}/monodroid/jni/osbridge.hh (100%) rename src/{ => native}/monodroid/jni/pinvoke-override-api.cc (100%) rename src/{ => native}/monodroid/jni/pinvoke-tables.include (100%) rename src/{ => native}/monodroid/jni/search.hh (100%) rename src/{ => native}/monodroid/jni/shared-constants.cc (100%) rename src/{ => native}/monodroid/jni/shared-constants.hh (100%) rename src/{ => native}/monodroid/jni/startup-aware-lock.hh (100%) rename src/{ => native}/monodroid/jni/strings.hh (100%) rename src/{ => native}/monodroid/jni/timezones.cc (100%) rename src/{ => native}/monodroid/jni/timing-internal.cc (100%) rename src/{ => native}/monodroid/jni/timing-internal.hh (100%) rename src/{ => native}/monodroid/jni/timing.hh (100%) rename src/{ => native}/monodroid/jni/util.cc (100%) rename src/{ => native}/monodroid/jni/util.hh (100%) rename src/{ => native}/monodroid/jni/win32/jni_md.h (100%) rename src/{ => native}/monodroid/jni/xa-internal-api-impl.hh (100%) rename src/{ => native}/monodroid/jni/xa-internal-api.cc (100%) rename src/{ => native}/monodroid/jni/xa-internal-api.hh (100%) rename src/{ => native}/monodroid/jni/xamarin-android-app-context.cc (100%) rename src/{ => native}/monodroid/jni/xamarin-app.hh (100%) rename src/{ => native}/monodroid/jni/xamarin_getifaddrs.cc (100%) rename src/{ => native}/monodroid/jni/xamarin_getifaddrs.h (100%) rename src/{ => native}/monodroid/jni/xxhash.hh (100%) rename src/{ => native}/monodroid/machine.config.xml (100%) rename src/{ => native}/monodroid/monodroid.csproj (100%) rename src/{ => native}/monodroid/monodroid.targets (100%) 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/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index b7a0a0daee3..58f8e95f3d9 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -1,17 +1,140 @@ -cmake_minimum_required(VERSION 3.19) +cmake_minimum_required(VERSION 3.21) # -# MUST be included before project()! +# Read product version # -include("../../build-tools/cmake/xa_preamble.cmake") +file(STRINGS "../../Directory.Build.props" XA_PRODUCT_VERSION_XML REGEX "^[ \t]*(.*)") +string(REGEX REPLACE "^[ \t]*(.*)" "\\1" XA_VERSION "${XA_PRODUCT_VERSION_XML}") project( - native-libs + android-native-bits VERSION ${XA_VERSION} - LANGUAGES CXX + DESCRIPTION "Xamarin.Android native runtime" + HOMEPAGE_URL "https://github.com/xamarin/xamarin-android" + LANGUAGES CXX C ) +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() + +# +# Needed modules +# +include(CheckIncludeFile) +include(CheckCXXSymbolExists) + +# +# General config +# +set(XA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Build${XA_BUILD_CONFIGURATION}") +include("${XA_BUILD_DIR}/xa_build_configuration.cmake") + # -# MUST be included after project()! +# 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(SHARED_SOURCES_DIR "${REPO_ROOT_DIR}/src/native/shared") +set(TRACING_SOURCES_DIR "${REPO_ROOT_DIR}/src/native/tracing") + # -include("../../build-tools/cmake/xa_common.cmake") +# Include directories +# +include_directories(SYSTEM ${CMAKE_SYSROOT}/usr/include/c++/v1/) +include_directories(SYSTEM "${NET_RUNTIME_DIR}/native/include/mono-2.0") +include_directories("${JAVA_INTEROP_SRC_PATH}") + +# +# Compiler defines +# +add_compile_definitions(XA_VERSION="${XA_VERSION}") +add_compile_definitions(_REENTRANT) +add_compile_definitions(PLATFORM_ANDROID) + +if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + add_compile_definitions(DEBUG) +endif() + +if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") + add_compile_definitions(ANDROID64) +endif() diff --git a/src/native/CMakePresets.json b/src/native/CMakePresets.json new file mode 100644 index 00000000000..a841c345e63 --- /dev/null +++ b/src/native/CMakePresets.json @@ -0,0 +1,309 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + + "configurePresets": { + { + "name": "common", + "hidden": true, + "generator": "Ninja", + "debug": true, + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "ANDROID_TOOLCHAIN": "clang" + } + }, + + { + "name": "common-debug", + "hidden": "true", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "XA_BUILD_CONFIGURATION": "Debug" + } + }, + + { + "name": "common-release", + "hidden": "true", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "XA_BUILD_CONFIGURATION": "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_RID": "android-arm" + } + }, + + { + "name": "common-arm64-v8a", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "arm64-v8a", + "ANDROID_RID": "android-arm64" + } + }, + + { + "name": "common-x86", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "x86", + "ANDROID_RID": "android-x86" + } + }, + + { + "name": "common-x86_64", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "x86_64", + "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/CMakeUserPresets.json b/src/native/CMakeUserPresets.json new file mode 100644 index 00000000000..bf93c770157 --- /dev/null +++ b/src/native/CMakeUserPresets.json @@ -0,0 +1,47 @@ +{ + "version": 3, + "configurePresets": { + { + "name": "common", + "toolchainFile": "@AndroidCmakeToolchainFile@", + "cacheVariables": { + "ANDROID_NDK": "@AndroidNdkDirectory@", + "CMAKE_MAKE_PROGRAM": "@NinjaPath@", + "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", + "OUTPUT_PATH": "@OutputPath@" + } + }, + + { + "name": "common-armeabi-v7a", + "cacheVariables": { + "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_Arm@", + "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_Arm@" + } + }, + + { + "name": "common-arm64-v8a", + "cacheVariables": { + "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_Arm64@", + "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_Arm64@" + } + }, + + { + "name": "common-x86", + "cacheVariables": { + "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_X86@", + "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_X86@" + } + }, + + { + "name": "common-x86_64", + "cacheVariables": { + "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_X86_64@", + "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_X86_64@" + } + } + } +} 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/libunwind-xamarin/CMakeLists.txt b/src/native/libunwind/CMakeLists.txt similarity index 100% rename from src/libunwind-xamarin/CMakeLists.txt rename to src/native/libunwind/CMakeLists.txt diff --git a/src/libunwind-xamarin/config.h.in b/src/native/libunwind/config.h.in similarity index 100% rename from src/libunwind-xamarin/config.h.in rename to src/native/libunwind/config.h.in diff --git a/src/libunwind-xamarin/fixes/aarch64/Gos-linux.c b/src/native/libunwind/fixes/aarch64/Gos-linux.c similarity index 100% rename from src/libunwind-xamarin/fixes/aarch64/Gos-linux.c rename to src/native/libunwind/fixes/aarch64/Gos-linux.c diff --git a/src/libunwind-xamarin/libunwind-xamarin.csproj b/src/native/libunwind/libunwind-xamarin.csproj similarity index 100% rename from src/libunwind-xamarin/libunwind-xamarin.csproj rename to src/native/libunwind/libunwind-xamarin.csproj diff --git a/src/libunwind-xamarin/libunwind-xamarin.targets b/src/native/libunwind/libunwind-xamarin.targets similarity index 100% rename from src/libunwind-xamarin/libunwind-xamarin.targets rename to src/native/libunwind/libunwind-xamarin.targets diff --git a/src/monodroid/.gitignore b/src/native/monodroid/.gitignore similarity index 100% rename from src/monodroid/.gitignore rename to src/native/monodroid/.gitignore diff --git a/src/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt similarity index 100% rename from src/monodroid/CMakeLists.txt rename to src/native/monodroid/CMakeLists.txt diff --git a/src/monodroid/config.xml b/src/native/monodroid/config.xml similarity index 100% rename from src/monodroid/config.xml rename to src/native/monodroid/config.xml diff --git a/src/monodroid/jni/.gitignore b/src/native/monodroid/jni/.gitignore similarity index 100% rename from src/monodroid/jni/.gitignore rename to src/native/monodroid/jni/.gitignore diff --git a/src/monodroid/jni/TODO.md b/src/native/monodroid/jni/TODO.md similarity index 100% rename from src/monodroid/jni/TODO.md rename to src/native/monodroid/jni/TODO.md diff --git a/src/monodroid/jni/android-system.cc b/src/native/monodroid/jni/android-system.cc similarity index 100% rename from src/monodroid/jni/android-system.cc rename to src/native/monodroid/jni/android-system.cc diff --git a/src/monodroid/jni/android-system.hh b/src/native/monodroid/jni/android-system.hh similarity index 100% rename from src/monodroid/jni/android-system.hh rename to src/native/monodroid/jni/android-system.hh diff --git a/src/monodroid/jni/application_dso_stub.cc b/src/native/monodroid/jni/application_dso_stub.cc similarity index 100% rename from src/monodroid/jni/application_dso_stub.cc rename to src/native/monodroid/jni/application_dso_stub.cc diff --git a/src/monodroid/jni/basic-android-system.cc b/src/native/monodroid/jni/basic-android-system.cc similarity index 100% rename from src/monodroid/jni/basic-android-system.cc rename to src/native/monodroid/jni/basic-android-system.cc diff --git a/src/monodroid/jni/basic-android-system.hh b/src/native/monodroid/jni/basic-android-system.hh similarity index 100% rename from src/monodroid/jni/basic-android-system.hh rename to src/native/monodroid/jni/basic-android-system.hh diff --git a/src/monodroid/jni/basic-utilities.cc b/src/native/monodroid/jni/basic-utilities.cc similarity index 100% rename from src/monodroid/jni/basic-utilities.cc rename to src/native/monodroid/jni/basic-utilities.cc diff --git a/src/monodroid/jni/basic-utilities.hh b/src/native/monodroid/jni/basic-utilities.hh similarity index 100% rename from src/monodroid/jni/basic-utilities.hh rename to src/native/monodroid/jni/basic-utilities.hh diff --git a/src/monodroid/jni/build-info.hh b/src/native/monodroid/jni/build-info.hh similarity index 100% rename from src/monodroid/jni/build-info.hh rename to src/native/monodroid/jni/build-info.hh diff --git a/src/monodroid/jni/config.h b/src/native/monodroid/jni/config.h similarity index 100% rename from src/monodroid/jni/config.h rename to src/native/monodroid/jni/config.h diff --git a/src/monodroid/jni/cpp-util.hh b/src/native/monodroid/jni/cpp-util.hh similarity index 100% rename from src/monodroid/jni/cpp-util.hh rename to src/native/monodroid/jni/cpp-util.hh diff --git a/src/monodroid/jni/cppcompat.hh b/src/native/monodroid/jni/cppcompat.hh similarity index 100% rename from src/monodroid/jni/cppcompat.hh rename to src/native/monodroid/jni/cppcompat.hh diff --git a/src/monodroid/jni/cpu-arch-detect.cc b/src/native/monodroid/jni/cpu-arch-detect.cc similarity index 100% rename from src/monodroid/jni/cpu-arch-detect.cc rename to src/native/monodroid/jni/cpu-arch-detect.cc diff --git a/src/monodroid/jni/cpu-arch.hh b/src/native/monodroid/jni/cpu-arch.hh similarity index 100% rename from src/monodroid/jni/cpu-arch.hh rename to src/native/monodroid/jni/cpu-arch.hh diff --git a/src/monodroid/jni/debug-app-helper.cc b/src/native/monodroid/jni/debug-app-helper.cc similarity index 100% rename from src/monodroid/jni/debug-app-helper.cc rename to src/native/monodroid/jni/debug-app-helper.cc diff --git a/src/monodroid/jni/debug-app-helper.hh b/src/native/monodroid/jni/debug-app-helper.hh similarity index 100% rename from src/monodroid/jni/debug-app-helper.hh rename to src/native/monodroid/jni/debug-app-helper.hh diff --git a/src/monodroid/jni/debug-constants.cc b/src/native/monodroid/jni/debug-constants.cc similarity index 100% rename from src/monodroid/jni/debug-constants.cc rename to src/native/monodroid/jni/debug-constants.cc diff --git a/src/monodroid/jni/debug.cc b/src/native/monodroid/jni/debug.cc similarity index 100% rename from src/monodroid/jni/debug.cc rename to src/native/monodroid/jni/debug.cc diff --git a/src/monodroid/jni/debug.hh b/src/native/monodroid/jni/debug.hh similarity index 100% rename from src/monodroid/jni/debug.hh rename to src/native/monodroid/jni/debug.hh diff --git a/src/monodroid/jni/designer-assemblies.cc b/src/native/monodroid/jni/designer-assemblies.cc similarity index 100% rename from src/monodroid/jni/designer-assemblies.cc rename to src/native/monodroid/jni/designer-assemblies.cc diff --git a/src/monodroid/jni/designer-assemblies.hh b/src/native/monodroid/jni/designer-assemblies.hh similarity index 100% rename from src/monodroid/jni/designer-assemblies.hh rename to src/native/monodroid/jni/designer-assemblies.hh diff --git a/src/monodroid/jni/embedded-assemblies-zip.cc b/src/native/monodroid/jni/embedded-assemblies-zip.cc similarity index 100% rename from src/monodroid/jni/embedded-assemblies-zip.cc rename to src/native/monodroid/jni/embedded-assemblies-zip.cc diff --git a/src/monodroid/jni/embedded-assemblies.cc b/src/native/monodroid/jni/embedded-assemblies.cc similarity index 100% rename from src/monodroid/jni/embedded-assemblies.cc rename to src/native/monodroid/jni/embedded-assemblies.cc diff --git a/src/monodroid/jni/embedded-assemblies.hh b/src/native/monodroid/jni/embedded-assemblies.hh similarity index 100% rename from src/monodroid/jni/embedded-assemblies.hh rename to src/native/monodroid/jni/embedded-assemblies.hh diff --git a/src/monodroid/jni/generate-pinvoke-tables.cc b/src/native/monodroid/jni/generate-pinvoke-tables.cc similarity index 100% rename from src/monodroid/jni/generate-pinvoke-tables.cc rename to src/native/monodroid/jni/generate-pinvoke-tables.cc diff --git a/src/monodroid/jni/globals.cc b/src/native/monodroid/jni/globals.cc similarity index 100% rename from src/monodroid/jni/globals.cc rename to src/native/monodroid/jni/globals.cc diff --git a/src/monodroid/jni/globals.hh b/src/native/monodroid/jni/globals.hh similarity index 100% rename from src/monodroid/jni/globals.hh rename to src/native/monodroid/jni/globals.hh diff --git a/src/monodroid/jni/host-config.h.in b/src/native/monodroid/jni/host-config.h.in similarity index 100% rename from src/monodroid/jni/host-config.h.in rename to src/native/monodroid/jni/host-config.h.in diff --git a/src/monodroid/jni/internal-pinvoke-api.cc b/src/native/monodroid/jni/internal-pinvoke-api.cc similarity index 100% rename from src/monodroid/jni/internal-pinvoke-api.cc rename to src/native/monodroid/jni/internal-pinvoke-api.cc diff --git a/src/monodroid/jni/jni-remapping.cc b/src/native/monodroid/jni/jni-remapping.cc similarity index 100% rename from src/monodroid/jni/jni-remapping.cc rename to src/native/monodroid/jni/jni-remapping.cc diff --git a/src/monodroid/jni/jni-remapping.hh b/src/native/monodroid/jni/jni-remapping.hh similarity index 100% rename from src/monodroid/jni/jni-remapping.hh rename to src/native/monodroid/jni/jni-remapping.hh diff --git a/src/monodroid/jni/jni-wrappers.hh b/src/native/monodroid/jni/jni-wrappers.hh similarity index 100% rename from src/monodroid/jni/jni-wrappers.hh rename to src/native/monodroid/jni/jni-wrappers.hh diff --git a/src/monodroid/jni/logger.cc b/src/native/monodroid/jni/logger.cc similarity index 100% rename from src/monodroid/jni/logger.cc rename to src/native/monodroid/jni/logger.cc diff --git a/src/monodroid/jni/logger.hh b/src/native/monodroid/jni/logger.hh similarity index 100% rename from src/monodroid/jni/logger.hh rename to src/native/monodroid/jni/logger.hh diff --git a/src/monodroid/jni/mono-image-loader.hh b/src/native/monodroid/jni/mono-image-loader.hh similarity index 100% rename from src/monodroid/jni/mono-image-loader.hh rename to src/native/monodroid/jni/mono-image-loader.hh diff --git a/src/monodroid/jni/mono-log-adapter.cc b/src/native/monodroid/jni/mono-log-adapter.cc similarity index 100% rename from src/monodroid/jni/mono-log-adapter.cc rename to src/native/monodroid/jni/mono-log-adapter.cc diff --git a/src/monodroid/jni/mono_android_Runtime.h b/src/native/monodroid/jni/mono_android_Runtime.h similarity index 100% rename from src/monodroid/jni/mono_android_Runtime.h rename to src/native/monodroid/jni/mono_android_Runtime.h diff --git a/src/monodroid/jni/monodroid-glue-designer.cc b/src/native/monodroid/jni/monodroid-glue-designer.cc similarity index 100% rename from src/monodroid/jni/monodroid-glue-designer.cc rename to src/native/monodroid/jni/monodroid-glue-designer.cc diff --git a/src/monodroid/jni/monodroid-glue-internal.hh b/src/native/monodroid/jni/monodroid-glue-internal.hh similarity index 100% rename from src/monodroid/jni/monodroid-glue-internal.hh rename to src/native/monodroid/jni/monodroid-glue-internal.hh diff --git a/src/monodroid/jni/monodroid-glue.cc b/src/native/monodroid/jni/monodroid-glue.cc similarity index 100% rename from src/monodroid/jni/monodroid-glue.cc rename to src/native/monodroid/jni/monodroid-glue.cc diff --git a/src/monodroid/jni/monodroid-glue.hh b/src/native/monodroid/jni/monodroid-glue.hh similarity index 100% rename from src/monodroid/jni/monodroid-glue.hh rename to src/native/monodroid/jni/monodroid-glue.hh diff --git a/src/monodroid/jni/monodroid-networkinfo.cc b/src/native/monodroid/jni/monodroid-networkinfo.cc similarity index 100% rename from src/monodroid/jni/monodroid-networkinfo.cc rename to src/native/monodroid/jni/monodroid-networkinfo.cc diff --git a/src/monodroid/jni/monodroid-tracing.cc b/src/native/monodroid/jni/monodroid-tracing.cc similarity index 100% rename from src/monodroid/jni/monodroid-tracing.cc rename to src/native/monodroid/jni/monodroid-tracing.cc diff --git a/src/monodroid/jni/monodroid.h b/src/native/monodroid/jni/monodroid.h similarity index 100% rename from src/monodroid/jni/monodroid.h rename to src/native/monodroid/jni/monodroid.h diff --git a/src/monodroid/jni/monodroid.x b/src/native/monodroid/jni/monodroid.x similarity index 100% rename from src/monodroid/jni/monodroid.x rename to src/native/monodroid/jni/monodroid.x diff --git a/src/monodroid/jni/monovm-properties.cc b/src/native/monodroid/jni/monovm-properties.cc similarity index 100% rename from src/monodroid/jni/monovm-properties.cc rename to src/native/monodroid/jni/monovm-properties.cc diff --git a/src/monodroid/jni/monovm-properties.hh b/src/native/monodroid/jni/monovm-properties.hh similarity index 100% rename from src/monodroid/jni/monovm-properties.hh rename to src/native/monodroid/jni/monovm-properties.hh diff --git a/src/monodroid/jni/osbridge.cc b/src/native/monodroid/jni/osbridge.cc similarity index 100% rename from src/monodroid/jni/osbridge.cc rename to src/native/monodroid/jni/osbridge.cc diff --git a/src/monodroid/jni/osbridge.hh b/src/native/monodroid/jni/osbridge.hh similarity index 100% rename from src/monodroid/jni/osbridge.hh rename to src/native/monodroid/jni/osbridge.hh diff --git a/src/monodroid/jni/pinvoke-override-api.cc b/src/native/monodroid/jni/pinvoke-override-api.cc similarity index 100% rename from src/monodroid/jni/pinvoke-override-api.cc rename to src/native/monodroid/jni/pinvoke-override-api.cc diff --git a/src/monodroid/jni/pinvoke-tables.include b/src/native/monodroid/jni/pinvoke-tables.include similarity index 100% rename from src/monodroid/jni/pinvoke-tables.include rename to src/native/monodroid/jni/pinvoke-tables.include diff --git a/src/monodroid/jni/search.hh b/src/native/monodroid/jni/search.hh similarity index 100% rename from src/monodroid/jni/search.hh rename to src/native/monodroid/jni/search.hh diff --git a/src/monodroid/jni/shared-constants.cc b/src/native/monodroid/jni/shared-constants.cc similarity index 100% rename from src/monodroid/jni/shared-constants.cc rename to src/native/monodroid/jni/shared-constants.cc diff --git a/src/monodroid/jni/shared-constants.hh b/src/native/monodroid/jni/shared-constants.hh similarity index 100% rename from src/monodroid/jni/shared-constants.hh rename to src/native/monodroid/jni/shared-constants.hh diff --git a/src/monodroid/jni/startup-aware-lock.hh b/src/native/monodroid/jni/startup-aware-lock.hh similarity index 100% rename from src/monodroid/jni/startup-aware-lock.hh rename to src/native/monodroid/jni/startup-aware-lock.hh diff --git a/src/monodroid/jni/strings.hh b/src/native/monodroid/jni/strings.hh similarity index 100% rename from src/monodroid/jni/strings.hh rename to src/native/monodroid/jni/strings.hh diff --git a/src/monodroid/jni/timezones.cc b/src/native/monodroid/jni/timezones.cc similarity index 100% rename from src/monodroid/jni/timezones.cc rename to src/native/monodroid/jni/timezones.cc diff --git a/src/monodroid/jni/timing-internal.cc b/src/native/monodroid/jni/timing-internal.cc similarity index 100% rename from src/monodroid/jni/timing-internal.cc rename to src/native/monodroid/jni/timing-internal.cc diff --git a/src/monodroid/jni/timing-internal.hh b/src/native/monodroid/jni/timing-internal.hh similarity index 100% rename from src/monodroid/jni/timing-internal.hh rename to src/native/monodroid/jni/timing-internal.hh diff --git a/src/monodroid/jni/timing.hh b/src/native/monodroid/jni/timing.hh similarity index 100% rename from src/monodroid/jni/timing.hh rename to src/native/monodroid/jni/timing.hh diff --git a/src/monodroid/jni/util.cc b/src/native/monodroid/jni/util.cc similarity index 100% rename from src/monodroid/jni/util.cc rename to src/native/monodroid/jni/util.cc diff --git a/src/monodroid/jni/util.hh b/src/native/monodroid/jni/util.hh similarity index 100% rename from src/monodroid/jni/util.hh rename to src/native/monodroid/jni/util.hh diff --git a/src/monodroid/jni/win32/jni_md.h b/src/native/monodroid/jni/win32/jni_md.h similarity index 100% rename from src/monodroid/jni/win32/jni_md.h rename to src/native/monodroid/jni/win32/jni_md.h diff --git a/src/monodroid/jni/xa-internal-api-impl.hh b/src/native/monodroid/jni/xa-internal-api-impl.hh similarity index 100% rename from src/monodroid/jni/xa-internal-api-impl.hh rename to src/native/monodroid/jni/xa-internal-api-impl.hh diff --git a/src/monodroid/jni/xa-internal-api.cc b/src/native/monodroid/jni/xa-internal-api.cc similarity index 100% rename from src/monodroid/jni/xa-internal-api.cc rename to src/native/monodroid/jni/xa-internal-api.cc diff --git a/src/monodroid/jni/xa-internal-api.hh b/src/native/monodroid/jni/xa-internal-api.hh similarity index 100% rename from src/monodroid/jni/xa-internal-api.hh rename to src/native/monodroid/jni/xa-internal-api.hh diff --git a/src/monodroid/jni/xamarin-android-app-context.cc b/src/native/monodroid/jni/xamarin-android-app-context.cc similarity index 100% rename from src/monodroid/jni/xamarin-android-app-context.cc rename to src/native/monodroid/jni/xamarin-android-app-context.cc diff --git a/src/monodroid/jni/xamarin-app.hh b/src/native/monodroid/jni/xamarin-app.hh similarity index 100% rename from src/monodroid/jni/xamarin-app.hh rename to src/native/monodroid/jni/xamarin-app.hh diff --git a/src/monodroid/jni/xamarin_getifaddrs.cc b/src/native/monodroid/jni/xamarin_getifaddrs.cc similarity index 100% rename from src/monodroid/jni/xamarin_getifaddrs.cc rename to src/native/monodroid/jni/xamarin_getifaddrs.cc diff --git a/src/monodroid/jni/xamarin_getifaddrs.h b/src/native/monodroid/jni/xamarin_getifaddrs.h similarity index 100% rename from src/monodroid/jni/xamarin_getifaddrs.h rename to src/native/monodroid/jni/xamarin_getifaddrs.h diff --git a/src/monodroid/jni/xxhash.hh b/src/native/monodroid/jni/xxhash.hh similarity index 100% rename from src/monodroid/jni/xxhash.hh rename to src/native/monodroid/jni/xxhash.hh diff --git a/src/monodroid/machine.config.xml b/src/native/monodroid/machine.config.xml similarity index 100% rename from src/monodroid/machine.config.xml rename to src/native/monodroid/machine.config.xml diff --git a/src/monodroid/monodroid.csproj b/src/native/monodroid/monodroid.csproj similarity index 100% rename from src/monodroid/monodroid.csproj rename to src/native/monodroid/monodroid.csproj diff --git a/src/monodroid/monodroid.targets b/src/native/monodroid/monodroid.targets similarity index 100% rename from src/monodroid/monodroid.targets rename to src/native/monodroid/monodroid.targets From 37c2108076d0795a0fa1cd1147317311db9e0d2a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 12 Apr 2024 12:33:39 +0200 Subject: [PATCH 07/49] [WIP] xaprepare generates cmake presets Neither runtime nor other native libraries are built yet --- Xamarin.Android.sln | 4 +- .../xaprepare/ConfigAndData/Configurables.cs | 1 + .../xaprepare/Steps/Step_GenerateFiles.cs | 26 ++++++++++ src/native/.gitignore | 2 + src/native/CMakeLists.txt | 1 + ...CMakePresets.json => CMakePresets.json.in} | 34 ++++++++++---- src/native/CMakeUserPresets.json | 47 ------------------- src/native/native.csproj | 22 +++++++++ 8 files changed, 77 insertions(+), 60 deletions(-) create mode 100644 src/native/.gitignore rename src/native/{CMakePresets.json => CMakePresets.json.in} (86%) delete mode 100644 src/native/CMakeUserPresets.json create mode 100644 src/native/native.csproj diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index b46ca2898aa..eaf3ea4fb2e 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -47,9 +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}") = "libunwind", "src\libunwind-xamarin\libunwind-xamarin.csproj", "{F8E4961B-C427-47F9-92D6-0BEB5B76B3D7}" -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/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 3cebe494ddb..3d51c65bb7d 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -206,6 +206,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/src/native/.gitignore b/src/native/.gitignore new file mode 100644 index 00000000000..34d21e62347 --- /dev/null +++ b/src/native/.gitignore @@ -0,0 +1,2 @@ +CMakeUserPresets.json +CMakePresets.json diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 58f8e95f3d9..494aac9e49e 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -111,6 +111,7 @@ 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") diff --git a/src/native/CMakePresets.json b/src/native/CMakePresets.json.in similarity index 86% rename from src/native/CMakePresets.json rename to src/native/CMakePresets.json.in index a841c345e63..51ae5802202 100644 --- a/src/native/CMakePresets.json +++ b/src/native/CMakePresets.json.in @@ -6,33 +6,39 @@ "patch": 0 }, - "configurePresets": { + "configurePresets": [ { "name": "common", "hidden": true, "generator": "Ninja", - "debug": true, + "debug": { + "output": true + }, + "toolchainFile": "@AndroidNdkDirectory@/build/cmake/android.toolchain.cmake", "cacheVariables": { + "ANDROID_NDK": "@AndroidNdkDirectory@", + "ANDROID_TOOLCHAIN": "clang", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", - "ANDROID_TOOLCHAIN": "clang" + "CMAKE_MAKE_PROGRAM": "@NinjaPath@", + "OUTPUT_PATH": "@OutputPath@", + "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", + "XA_BUILD_CONFIGURATION": "@XA_BUILD_CONFIGURATION@" } }, { "name": "common-debug", - "hidden": "true", + "hidden": true, "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "XA_BUILD_CONFIGURATION": "Debug" + "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "common-release", - "hidden": "true", + "hidden": true, "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release", - "XA_BUILD_CONFIGURATION": "Release" + "CMAKE_BUILD_TYPE": "Release" } }, @@ -85,6 +91,8 @@ "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" } }, @@ -94,6 +102,8 @@ "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" } }, @@ -103,6 +113,8 @@ "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" } }, @@ -112,6 +124,8 @@ "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" } }, @@ -305,5 +319,5 @@ "name": "ubsan-debug-x86_64", "inherits": ["analyzers-debug-x86_64", "ubsan-common"] } - } + ] } diff --git a/src/native/CMakeUserPresets.json b/src/native/CMakeUserPresets.json deleted file mode 100644 index bf93c770157..00000000000 --- a/src/native/CMakeUserPresets.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "version": 3, - "configurePresets": { - { - "name": "common", - "toolchainFile": "@AndroidCmakeToolchainFile@", - "cacheVariables": { - "ANDROID_NDK": "@AndroidNdkDirectory@", - "CMAKE_MAKE_PROGRAM": "@NinjaPath@", - "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", - "OUTPUT_PATH": "@OutputPath@" - } - }, - - { - "name": "common-armeabi-v7a", - "cacheVariables": { - "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_Arm@", - "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_Arm@" - } - }, - - { - "name": "common-arm64-v8a", - "cacheVariables": { - "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_Arm64@", - "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_Arm64@" - } - }, - - { - "name": "common-x86", - "cacheVariables": { - "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_X86@", - "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_X86@" - } - }, - - { - "name": "common-x86_64", - "cacheVariables": { - "ANDROID_NATIVE_API_LEVEL": "@AndroidNdkApiLevel_X86_64@", - "ANDROID_PLATFORM": "android-@AndroidNdkApiLevel_X86_64@" - } - } - } -} diff --git a/src/native/native.csproj b/src/native/native.csproj new file mode 100644 index 00000000000..38b77115100 --- /dev/null +++ b/src/native/native.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0 + Debug + AnyCPU + Exe + false + + + + + + $(MicrosoftAndroidSdkOutDir)lib\ + + + + + + + + From eb0628fd943d35b10fccd8f574dc7daa6a4bbf80 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 12 Apr 2024 19:29:53 +0200 Subject: [PATCH 08/49] [WIP] cmake stuff Some libs build already. monodroid still not built. --- external/libunwind | 2 +- src/native/CMakeLists.txt | 304 ++++++++++++++++++++++++++-- src/native/libstub/CMakeLists.txt | 44 ++++ src/native/libunwind/CMakeLists.txt | 157 +++++++------- src/native/native.targets | 199 ++++++++++++++++++ src/native/shared/CMakeLists.txt | 45 ++++ src/native/shared/helpers.hh | 2 +- 7 files changed, 651 insertions(+), 102 deletions(-) create mode 100644 src/native/libstub/CMakeLists.txt create mode 100644 src/native/native.targets create mode 100644 src/native/shared/CMakeLists.txt diff --git a/external/libunwind b/external/libunwind index 3705baed4dd..9cc4d98b22a 160000 --- a/external/libunwind +++ b/external/libunwind @@ -1 +1 @@ -Subproject commit 3705baed4ddb5a98138d16dd2effcaeaa7e72db5 +Subproject commit 9cc4d98b22ae57bc1d8c253988feb85d4298a634 diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 494aac9e49e..9d465d16ba6 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -11,9 +11,27 @@ project( VERSION ${XA_VERSION} DESCRIPTION "Xamarin.Android native runtime" HOMEPAGE_URL "https://github.com/xamarin/xamarin-android" - LANGUAGES CXX C + 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(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) @@ -83,8 +101,11 @@ endif() # # Needed modules # -include(CheckIncludeFile) -include(CheckCXXSymbolExists) +# include(CheckIncludeFile) +# include(CheckCXXSymbolExists) +include(CheckCXXCompilerFlag) +include(CheckCCompilerFlag) +include(CheckLinkerFlag) # # General config @@ -112,30 +133,285 @@ else() endif() -file(REAL_PATH "../../../" REPO_ROOT_DIR) +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(SHARED_SOURCES_DIR "${REPO_ROOT_DIR}/src/native/shared") -set(TRACING_SOURCES_DIR "${REPO_ROOT_DIR}/src/native/tracing") +set(LIBUNWIND_SOURCE_DIR "${EXTERNAL_DIR}/libunwind") + # # Include directories # -include_directories(SYSTEM ${CMAKE_SYSROOT}/usr/include/c++/v1/) -include_directories(SYSTEM "${NET_RUNTIME_DIR}/native/include/mono-2.0") -include_directories("${JAVA_INTEROP_SRC_PATH}") +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 # -add_compile_definitions(XA_VERSION="${XA_VERSION}") -add_compile_definitions(_REENTRANT) -add_compile_definitions(PLATFORM_ANDROID) +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(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") - add_compile_definitions(ANDROID64) +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() + +# +# 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() + +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}") + +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(libstub) +add_subdirectory(shared) +add_subdirectory(libunwind) 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/native/libunwind/CMakeLists.txt b/src/native/libunwind/CMakeLists.txt index 02ad008d774..11ffeda2095 100644 --- a/src/native/libunwind/CMakeLists.txt +++ b/src/native/libunwind/CMakeLists.txt @@ -1,25 +1,6 @@ -cmake_minimum_required(VERSION 3.19) - -# -# MUST be included before project()! -# -include("../../build-tools/cmake/xa_preamble.cmake") - -if(NOT DEFINED LIBUNWIND_LIBRARY_NAME) - message(FATAL_ERROR "Please set the LIBUNWIND_LIBRARY_NAME variable on command line (-DLIBUNWIND_LIBRARY_NAME=base_library_name)") -endif() - -if(NOT DEFINED LIBUNWIND_SOURCE_DIR) - message(FATAL_ERROR "Please set the LIBUNWIND_SOURCE_DIR variable on command line (-DLIBUNWIND_SOURCE_DIR=source_dir_path)") -endif() - -if(NOT DEFINED LIBUNWIND_OUTPUT_DIR) - message(FATAL_ERROR "Please set the LIBUNWIND_OUTPUT_DIR variable on command line (-DLIBUNWIND_OUTPUT_DIR=output_dir_path)") -endif() - -if(NOT DEFINED LIBUNWIND_HEADERS_OUTPUT_DIR) - message(FATAL_ERROR "Please set the LIBUNWIND_HEADERS_OUTPUT_DIR variable on command line (-DLIBUNWIND_HEADERS_OUTPUT_DIR=output_dir_path)") -endif() +ensure_variable_set(LIBUNWIND_SOURCE_DIR) +set(LIB_NAME unwind-xamarin) +set(LIB_ALIAS xa::unwind) # # Read libunwind version @@ -38,27 +19,11 @@ set(PKG_EXTRA "${UNWIND_EXTRA_VERSION}") set(PACKAGE_STRING "libunwind-xamarin") set(PACKAGE_BUGREPORT "") -message(STATUS "Major: ${PKG_MAJOR}; Minor: ${PKG_MINOR}; Extra: ${PKG_EXTRA}") - -project( - libunwind-xamarin -# VERSION "${PKG_MAJOR}.${PKG_MINOR}.${PKG_EXTRA}" - LANGUAGES C ASM -) - -# -# MUST be included after project()! -# -include("../../build-tools/cmake/xa_common.cmake") +message(STATUS "libunwind version: ${PKG_MAJOR}.${PKG_MINOR}.${PKG_EXTRA}") include(CheckCSourceCompiles) include(CheckIncludeFiles) include(CheckSymbolExists) -include("../../build-tools/cmake/xa_macros.cmake") - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_OUTPUT_DIR}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_OUTPUT_DIR}) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_OUTPUT_DIR}) if(CMAKE_ANDROID_ARCH_ABI STREQUAL arm64-v8a) set(TARGET_AARCH64 TRUE) @@ -76,30 +41,19 @@ else() message(FATAL_ERROR "Unsupported Android ABI ${CMAKE_ANDROID_ARCH_ABI}") endif() -set(DSO_SYMBOL_VISIBILITY "hidden") -xa_common_prepare() - -if(CMAKE_BUILD_TYPE STREQUAL Debug) - list(APPEND LOCAL_COMPILER_ARGS -g -fno-omit-frame-pointer) +if(IS_DEBUG) + list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS -g -fno-omit-frame-pointer) else() - list(APPEND LOCAL_COMPILER_ARGS -s -fomit-frame-pointer) + list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS -fomit-frame-pointer) add_compile_definitions(NDEBUG) endif() -list(APPEND LOCAL_COMPILER_ARGS - ${XA_DEFAULT_SYMBOL_VISIBILITY} +list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS -fno-asynchronous-unwind-tables -fno-unwind-tables + -Wno-macro-redefined ) -xa_check_c_flags(XA_C_FLAGS "${LOCAL_COMPILER_ARGS}") -xa_check_c_linker_flags(XA_C_LINKER_FLAGS "${LOCAL_COMPILER_ARGS}") - -add_compile_options(${XA_C_FLAGS}) -add_link_options(${XA_C_LINKER_FLAGS}) - -add_compile_definitions(HAVE_CONFIG_H) -add_compile_definitions(_GNU_SOURCE) -add_compile_definitions(UNW_LOCAL_ONLY) # we don't need remote unwinding +xa_check_c_args(LIBUNWIND_C_ARGS "${POTENTIAL_LOCAL_COMPILER_ARGS}") # Detect include files set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) @@ -126,34 +80,6 @@ configure_file(${LIBUNWIND_SOURCE_DIR}/include/libunwind-common.h.in ${CMAKE_CUR 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) -# The files are nearly identical, the only difference is name of the header included when remote-only libunwind is used -# We don't use it, but we still copy files to separate directories in order to avoid locking issues during parallel builds -set(HEADERS_DIR ${LIBUNWIND_HEADERS_OUTPUT_DIR}/${CMAKE_ANDROID_ARCH_ABI}) - -file(COPY ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind-common.h DESTINATION ${HEADERS_DIR}) -file(COPY ${CMAKE_CURRENT_BINARY_DIR}/include/libunwind.h DESTINATION ${HEADERS_DIR}) -file(COPY ${CMAKE_CURRENT_BINARY_DIR}/include/tdep/libunwind_i.h DESTINATION ${HEADERS_DIR}/tdep/) - -include_directories(${LIBUNWIND_SOURCE_DIR}/include/tdep) -include_directories(${LIBUNWIND_SOURCE_DIR}/include) -include_directories(${LIBUNWIND_SOURCE_DIR}/src) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/tdep) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) - -if(TARGET_ARM) - # Ensure that the remote and local unwind code can reside in the same binary without name clashing - add_definitions("-Darm_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 - include_directories(${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() - set(SOURCES_DIR ${LIBUNWIND_SOURCE_DIR}/src) set(LIBUNWIND_XAMARIN_SOURCES @@ -384,12 +310,71 @@ if(TARGET_AARCH64) ) endif() -add_library(${LIBUNWIND_LIBRARY_NAME} +add_library( + ${LIB_NAME} STATIC ${LIBUNWIND_XAMARIN_SOURCES} ) +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +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( - ${LIBUNWIND_LIBRARY_NAME} + ${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/native.targets b/src/native/native.targets new file mode 100644 index 00000000000..97394fd5c65 --- /dev/null +++ b/src/native/native.targets @@ -0,0 +1,199 @@ + + + + + + + + + <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="libstub\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="libunwind\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="monodroid\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="shared\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="tracing\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')" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> + + + + + + <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON + <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF + + <_CmakeAndroidFlags>$(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset default-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release + + + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset asan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset asan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset ubsan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset ubsan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release + + + + + + + + + + + + <_MonoDroidSources Include="jni\*.cc;jni\*.h;jni\*.hh;jni\**\*.c;" /> + + + + + + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> + <_BuildAndroidRuntimesInputs Include="@(_MonoDroidSources)" /> + <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.debug.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.release.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app.so')" /> + + + <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+ubsan.debug.so')" /> + <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+asan.debug.so')" /> + <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+asan.release.so')" /> + <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+ubsan.release.so')" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ArmRuntimePackFiles Include="$(OutputPath)\android-arm\*.*" /> + <_Arm64RuntimePackFiles Include="$(OutputPath)\android-arm64\*.*" /> + <_x86RuntimePackFiles Include="$(OutputPath)\android-x86\*.*" /> + <_x64RuntimePackFiles Include="$(OutputPath)\android-x64\*.*" /> + + + + + + + + diff --git a/src/native/shared/CMakeLists.txt b/src/native/shared/CMakeLists.txt new file mode 100644 index 00000000000..54620d837ac --- /dev/null +++ b/src/native/shared/CMakeLists.txt @@ -0,0 +1,45 @@ +set(LIB_NAME xa-shared-bits) +set(LIB_ALIAS xa::shared) + +set(XA_SHARED_SOURCES + cxx-abi/string.cc + cxx-abi/terminate.cc + helpers.cc + new_delete.cc +) + +add_library( + ${LIB_NAME} + STATIC + ${XA_SHARED_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/shared/helpers.hh b/src/native/shared/helpers.hh index fe5b03ecda1..40eff78eaca 100644 --- a/src/native/shared/helpers.hh +++ b/src/native/shared/helpers.hh @@ -4,7 +4,7 @@ #include #include -#include "java-interop-util.h" +#include #include "platform-compat.hh" namespace xamarin::android From 5756ecded4319ab5e8fc8a1a37bdea691f65e1bd Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 15 Apr 2024 22:31:20 +0200 Subject: [PATCH 09/49] Refactoring + cleanup continue --- src/native/CMakeLists.txt | 4 +- src/native/libunwind/CMakeLists.txt | 5 + src/native/monodroid/CMakeLists.txt | 69 +-- src/native/monodroid/jni/android-system.hh | 139 ------ .../monodroid/jni/basic-android-system.cc | 109 ----- .../monodroid/jni/basic-android-system.hh | 110 ----- src/native/monodroid/jni/basic-utilities.hh | 343 --------------- src/native/monodroid/jni/debug.hh | 16 - src/native/monodroid/jni/monodroid-glue.cc | 10 +- src/native/monodroid/jni/osbridge.cc | 6 - src/native/monodroid/jni/runtime-util.cc | 20 + src/native/monodroid/jni/runtime-util.hh | 13 + src/native/monodroid/jni/timing.cc | 11 + src/native/monodroid/jni/util.cc | 188 -------- src/native/monodroid/jni/util.hh | 110 ----- src/native/runtime-base/CMakeLists.txt | 60 +++ .../jni => runtime-base}/android-system.cc | 209 ++++++--- src/native/runtime-base/android-system.hh | 233 ++++++++++ .../jni => runtime-base}/cpu-arch-detect.cc | 0 .../jni => runtime-base}/cpu-arch.hh | 2 - .../jni => runtime-base}/jni-wrappers.hh | 0 .../{monodroid/jni => runtime-base}/logger.cc | 26 +- .../{monodroid/jni => runtime-base}/logger.hh | 0 .../jni => runtime-base}/shared-constants.cc | 0 .../jni => runtime-base}/shared-constants.hh | 15 + .../jni => runtime-base}/strings.hh | 0 .../util.cc} | 188 +++++++- src/native/runtime-base/util.hh | 405 ++++++++++++++++++ src/native/shared/CMakeLists.txt | 5 + .../{monodroid/jni => shared}/cpp-util.hh | 0 .../{monodroid/jni => shared}/xxhash.hh | 0 src/native/xamarin-app-stub/CMakeLists.txt | 47 ++ .../application_dso_stub.cc | 0 .../jni => xamarin-app-stub}/xamarin-app.hh | 2 +- 34 files changed, 1166 insertions(+), 1179 deletions(-) delete mode 100644 src/native/monodroid/jni/android-system.hh delete mode 100644 src/native/monodroid/jni/basic-android-system.cc delete mode 100644 src/native/monodroid/jni/basic-android-system.hh delete mode 100644 src/native/monodroid/jni/basic-utilities.hh create mode 100644 src/native/monodroid/jni/runtime-util.cc create mode 100644 src/native/monodroid/jni/runtime-util.hh create mode 100644 src/native/monodroid/jni/timing.cc delete mode 100644 src/native/monodroid/jni/util.cc delete mode 100644 src/native/monodroid/jni/util.hh create mode 100644 src/native/runtime-base/CMakeLists.txt rename src/native/{monodroid/jni => runtime-base}/android-system.cc (70%) create mode 100644 src/native/runtime-base/android-system.hh rename src/native/{monodroid/jni => runtime-base}/cpu-arch-detect.cc (100%) rename src/native/{monodroid/jni => runtime-base}/cpu-arch.hh (95%) rename src/native/{monodroid/jni => runtime-base}/jni-wrappers.hh (100%) rename src/native/{monodroid/jni => runtime-base}/logger.cc (92%) rename src/native/{monodroid/jni => runtime-base}/logger.hh (100%) rename src/native/{monodroid/jni => runtime-base}/shared-constants.cc (100%) rename src/native/{monodroid/jni => runtime-base}/shared-constants.hh (81%) rename src/native/{monodroid/jni => runtime-base}/strings.hh (100%) rename src/native/{monodroid/jni/basic-utilities.cc => runtime-base/util.cc} (50%) create mode 100644 src/native/runtime-base/util.hh rename src/native/{monodroid/jni => shared}/cpp-util.hh (100%) rename src/native/{monodroid/jni => shared}/xxhash.hh (100%) create mode 100644 src/native/xamarin-app-stub/CMakeLists.txt rename src/native/{monodroid/jni => xamarin-app-stub}/application_dso_stub.cc (100%) rename src/native/{monodroid/jni => xamarin-app-stub}/xamarin-app.hh (99%) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 9d465d16ba6..7a35a5133f8 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -413,5 +413,7 @@ add_link_options("$<$:${COMMON_CXX_LINKER_ARGS}>") add_link_options("$<$:${COMMON_C_LINKER_ARGS}>") add_subdirectory(libstub) -add_subdirectory(shared) add_subdirectory(libunwind) +add_subdirectory(shared) +add_subdirectory(xamarin-app-stub) +add_subdirectory(runtime-base) diff --git a/src/native/libunwind/CMakeLists.txt b/src/native/libunwind/CMakeLists.txt index 11ffeda2095..cfdb3408d9c 100644 --- a/src/native/libunwind/CMakeLists.txt +++ b/src/native/libunwind/CMakeLists.txt @@ -50,7 +50,12 @@ 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-single-bit-bitfield-constant-conversion ) xa_check_c_args(LIBUNWIND_C_ARGS "${POTENTIAL_LOCAL_COMPILER_ARGS}") diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index a82cddea564..1f312c8bf7e 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -22,12 +22,6 @@ option(ENABLE_TIMING "Build with timing support" OFF) # 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() @@ -63,10 +57,7 @@ set(SOURCES_DIR ${CMAKE_SOURCE_DIR}/jni) set(BIONIC_SOURCES_DIR "${REPO_ROOT_DIR}/src-ThirdParty/bionic") set(LZ4_SRC_DIR "${EXTERNAL_DIR}/lz4/lib") set(LZ4_INCLUDE_DIR ${LZ4_SRC_DIR}) -set(XA_BIN_DIR "${REPO_ROOT_DIR}/bin/${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") set(LZ4_SOURCES "${LZ4_SRC_DIR}/lz4.c" @@ -81,21 +72,8 @@ include_directories(${EXTERNAL_DIR}) include_directories(SYSTEM ${CONSTEXPR_XXH3_DIR}) include_directories(SYSTEM ${ROBIN_MAP_DIR}/include) include_directories(SYSTEM ${LZ4_INCLUDE_DIR}) - 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") - -# Common preparation code -include("../../build-tools/cmake/xa_macros.cmake") -xa_common_prepare() -xa_macos_prepare_arm64() # Compiler defines @@ -285,9 +263,6 @@ set(XAMARIN_MONODROID_SOURCES ${JAVA_INTEROP_SRC_PATH}/java-interop.cc ${LZ4_SOURCES} ${XA_SHARED_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 @@ -303,10 +278,10 @@ set(XAMARIN_MONODROID_SOURCES ${SOURCES_DIR}/monovm-properties.cc ${SOURCES_DIR}/osbridge.cc ${SOURCES_DIR}/pinvoke-override-api.cc + ${SOURCES_DIR}/runtime-util.cc ${SOURCES_DIR}/shared-constants.cc ${SOURCES_DIR}/timezones.cc ${SOURCES_DIR}/timing-internal.cc - ${SOURCES_DIR}/util.cc ${SOURCES_DIR}/xamarin_getifaddrs.cc ) @@ -476,43 +451,5 @@ target_link_options( 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() + ${LINK_LIBS} xa::xamarin-app +) diff --git a/src/native/monodroid/jni/android-system.hh b/src/native/monodroid/jni/android-system.hh deleted file mode 100644 index 1b62b8c74ab..00000000000 --- a/src/native/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/native/monodroid/jni/basic-android-system.cc b/src/native/monodroid/jni/basic-android-system.cc deleted file mode 100644 index e9dbbac2d0e..00000000000 --- a/src/native/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/native/monodroid/jni/basic-android-system.hh b/src/native/monodroid/jni/basic-android-system.hh deleted file mode 100644 index 9b6f1bc851f..00000000000 --- a/src/native/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/native/monodroid/jni/basic-utilities.hh b/src/native/monodroid/jni/basic-utilities.hh deleted file mode 100644 index 51a42741ed0..00000000000 --- a/src/native/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/native/monodroid/jni/debug.hh b/src/native/monodroid/jni/debug.hh index 9eafaa05624..4eef337b3f0 100644 --- a/src/native/monodroid/jni/debug.hh +++ b/src/native/monodroid/jni/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 () {} diff --git a/src/native/monodroid/jni/monodroid-glue.cc b/src/native/monodroid/jni/monodroid-glue.cc index 1de65c5c46d..53fbdc7b721 100644 --- a/src/native/monodroid/jni/monodroid-glue.cc +++ b/src/native/monodroid/jni/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" @@ -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; @@ -878,7 +879,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec 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;"); @@ -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); @@ -1607,7 +1608,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl 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); + java_TimeZone = RuntimeUtil::get_class_from_runtime_field (env, klass, "java_util_TimeZone", true); utils.monodroid_store_package_name (application_config.android_package_name); @@ -1738,6 +1739,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/native/monodroid/jni/osbridge.cc b/src/native/monodroid/jni/osbridge.cc index dc8d50db6d3..50e3d560b92 100644 --- a/src/native/monodroid/jni/osbridge.cc +++ b/src/native/monodroid/jni/osbridge.cc @@ -18,12 +18,6 @@ #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; - using namespace xamarin::android; using namespace xamarin::android::internal; diff --git a/src/native/monodroid/jni/runtime-util.cc b/src/native/monodroid/jni/runtime-util.cc new file mode 100644 index 00000000000..0fc8edc4482 --- /dev/null +++ b/src/native/monodroid/jni/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/jni/runtime-util.hh b/src/native/monodroid/jni/runtime-util.hh new file mode 100644 index 00000000000..8e6a39b4195 --- /dev/null +++ b/src/native/monodroid/jni/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/native/monodroid/jni/timing.cc b/src/native/monodroid/jni/timing.cc new file mode 100644 index 00000000000..ec48972850b --- /dev/null +++ b/src/native/monodroid/jni/timing.cc @@ -0,0 +1,11 @@ +#include "timing-internal.hh" + +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/native/monodroid/jni/util.cc b/src/native/monodroid/jni/util.cc deleted file mode 100644 index b7bcdd805b5..00000000000 --- a/src/native/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/native/monodroid/jni/util.hh b/src/native/monodroid/jni/util.hh deleted file mode 100644 index d402a01484e..00000000000 --- a/src/native/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/native/runtime-base/CMakeLists.txt b/src/native/runtime-base/CMakeLists.txt new file mode 100644 index 00000000000..a10a50da582 --- /dev/null +++ b/src/native/runtime-base/CMakeLists.txt @@ -0,0 +1,60 @@ +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 +) + +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 + xa::shared + 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/native/monodroid/jni/android-system.cc b/src/native/runtime-base/android-system.cc similarity index 70% rename from src/native/monodroid/jni/android-system.cc rename to src/native/runtime-base/android-system.cc index fce00bae049..c6643b7e19f 100644 --- a/src/native/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) { @@ -122,7 +130,7 @@ 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; @@ -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) { @@ -164,7 +172,7 @@ AndroidSystem::monodroid_get_system_property (const char *name, dynamic_local_st } 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; @@ -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; @@ -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/native/monodroid/jni/cpu-arch-detect.cc b/src/native/runtime-base/cpu-arch-detect.cc similarity index 100% rename from src/native/monodroid/jni/cpu-arch-detect.cc rename to src/native/runtime-base/cpu-arch-detect.cc diff --git a/src/native/monodroid/jni/cpu-arch.hh b/src/native/runtime-base/cpu-arch.hh similarity index 95% rename from src/native/monodroid/jni/cpu-arch.hh rename to src/native/runtime-base/cpu-arch.hh index 29c210d47f4..de0e9cf93d5 100644 --- a/src/native/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/native/monodroid/jni/jni-wrappers.hh b/src/native/runtime-base/jni-wrappers.hh similarity index 100% rename from src/native/monodroid/jni/jni-wrappers.hh rename to src/native/runtime-base/jni-wrappers.hh diff --git a/src/native/monodroid/jni/logger.cc b/src/native/runtime-base/logger.cc similarity index 92% rename from src/native/monodroid/jni/logger.cc rename to src/native/runtime-base/logger.cc index 581d633df99..db3c4fc47ca 100644 --- a/src/native/monodroid/jni/logger.cc +++ b/src/native/runtime-base/logger.cc @@ -7,14 +7,12 @@ #include #include +#include +#include "android-system.hh" #include "logger.hh" - -#include "monodroid.h" -#include "monodroid-glue.hh" -#include "debug.hh" +#include "shared-constants.hh" #include "util.hh" -#include "globals.hh" #undef DO_LOG #define DO_LOG(_level_,_category_,_format_,_args_) \ @@ -67,17 +65,17 @@ open_file (LogCategories category, const char *path, const char *override_dir, c } if (!path) { - utils.create_public_directory (override_dir); - p = utils.path_combine (override_dir, filename); + Util::create_public_directory (override_dir); + p = Util::path_combine (override_dir, filename); path = p; } unlink (path); - f = utils.monodroid_fopen (path, "a"); + f = Util::monodroid_fopen (path, "a"); if (f) { - utils.set_world_accessable (path); + Util::set_world_accessable (path); } else { log_warn (category, "Could not open path '%s' for logging: %s", path, strerror (errno)); } @@ -132,7 +130,7 @@ init_logging_categories (char*& mono_log_mask, char*& mono_log_level) log_timing_categories = LOG_TIMING_DEFAULT; dynamic_local_string value; - if (androidSystem.monodroid_get_system_property (Debug::DEBUG_MONO_LOG_PROPERTY, value) == 0) + if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_LOG_PROPERTY, value) == 0) return; string_segment param; @@ -182,7 +180,7 @@ init_logging_categories (char*& mono_log_mask, char*& mono_log_level) 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 ()); + gref_file = Util::strdup_new (param, CAT_GREF_EQUALS.length ()); continue; } @@ -198,7 +196,7 @@ init_logging_categories (char*& mono_log_mask, char*& mono_log_level) 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 ()); + lref_file = Util::strdup_new (param, CAT_LREF_EQUALS.length ()); continue; } @@ -226,13 +224,13 @@ init_logging_categories (char*& mono_log_mask, char*& mono_log_level) 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 ()); + 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 = utils.strdup_new (param, MONO_LOG_LEVEL_ARG.length ()); + mono_log_level = Util::strdup_new (param, MONO_LOG_LEVEL_ARG.length ()); continue; } diff --git a/src/native/monodroid/jni/logger.hh b/src/native/runtime-base/logger.hh similarity index 100% rename from src/native/monodroid/jni/logger.hh rename to src/native/runtime-base/logger.hh diff --git a/src/native/monodroid/jni/shared-constants.cc b/src/native/runtime-base/shared-constants.cc similarity index 100% rename from src/native/monodroid/jni/shared-constants.cc rename to src/native/runtime-base/shared-constants.cc diff --git a/src/native/monodroid/jni/shared-constants.hh b/src/native/runtime-base/shared-constants.hh similarity index 81% rename from src/native/monodroid/jni/shared-constants.hh rename to src/native/runtime-base/shared-constants.hh index 1ecdbcf90e5..bc8461f59f0 100644 --- a/src/native/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" }; diff --git a/src/native/monodroid/jni/strings.hh b/src/native/runtime-base/strings.hh similarity index 100% rename from src/native/monodroid/jni/strings.hh rename to src/native/runtime-base/strings.hh diff --git a/src/native/monodroid/jni/basic-utilities.cc b/src/native/runtime-base/util.cc similarity index 50% rename from src/native/monodroid/jni/basic-utilities.cc rename to src/native/runtime-base/util.cc index bfe10dfa922..a5ff68f04a8 100644 --- a/src/native/monodroid/jni/basic-utilities.cc +++ b/src/native/runtime-base/util.cc @@ -1,15 +1,161 @@ #include -#include #include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include -#include "basic-utilities.hh" -#include "logger.hh" -#include "cpp-util.hh" +#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); +} + +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; +} + 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"); @@ -31,7 +177,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 +188,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 +222,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 +235,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 +248,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 +257,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 +270,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 +311,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 +321,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 +338,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 +359,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)); @@ -286,7 +432,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 +444,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..49c230e5bf0 --- /dev/null +++ b/src/native/runtime-base/util.hh @@ -0,0 +1,405 @@ +// 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 void monodroid_store_package_name (const char *name); + 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& str, std::string_view const& sv) 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 + 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 = ADD_WITH_OVERFLOW_CHECK (size_t, 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 void package_hash_to_hex (IdxType idx); + + template + static void package_hash_to_hex (uint32_t hash, IdxType idx, Indices... indices); + + template + static constexpr void assert_char_type () + { + static_assert (std::is_same_v, "CharType must be an 8-bit character type"); + } + + private: + static char package_property_suffix[9]; + 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 index 54620d837ac..0dcfce8bbe3 100644 --- a/src/native/shared/CMakeLists.txt +++ b/src/native/shared/CMakeLists.txt @@ -8,6 +8,9 @@ set(XA_SHARED_SOURCES new_delete.cc ) +set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") +set(CONSTEXPR_XXH3_DIR "${EXTERNAL_DIR}/constexpr-xxh3") + add_library( ${LIB_NAME} STATIC @@ -21,6 +24,8 @@ target_include_directories( PUBLIC "$" "$" + "$" + "$" ) target_include_directories( diff --git a/src/native/monodroid/jni/cpp-util.hh b/src/native/shared/cpp-util.hh similarity index 100% rename from src/native/monodroid/jni/cpp-util.hh rename to src/native/shared/cpp-util.hh diff --git a/src/native/monodroid/jni/xxhash.hh b/src/native/shared/xxhash.hh similarity index 100% rename from src/native/monodroid/jni/xxhash.hh rename to src/native/shared/xxhash.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..ff40ebcc227 --- /dev/null +++ b/src/native/xamarin-app-stub/CMakeLists.txt @@ -0,0 +1,47 @@ +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}) + +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_libraries( + ${LIB_NAME} + PRIVATE + xa::shared +) + +set_target_properties( + ${LIB_NAME} + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native/monodroid/jni/application_dso_stub.cc b/src/native/xamarin-app-stub/application_dso_stub.cc similarity index 100% rename from src/native/monodroid/jni/application_dso_stub.cc rename to src/native/xamarin-app-stub/application_dso_stub.cc diff --git a/src/native/monodroid/jni/xamarin-app.hh b/src/native/xamarin-app-stub/xamarin-app.hh similarity index 99% rename from src/native/monodroid/jni/xamarin-app.hh rename to src/native/xamarin-app-stub/xamarin-app.hh index 7d454880faf..09301170515 100644 --- a/src/native/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 From d6ba6244461c3dfa2628058c2155303559a20de3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 16 Apr 2024 13:19:47 +0200 Subject: [PATCH 10/49] Most libs are built from separate directories now --- src/native/CMakeLists.txt | 5 + src/native/java-interop/CMakeLists.txt | 45 +++++++++ src/native/monodroid/CMakeLists.txt | 11 +-- src/native/monodroid/jni/debug.cc | 23 ----- src/native/monodroid/jni/debug.hh | 13 --- src/native/runtime-base/logger.cc | 98 ++++++++++++------- src/native/runtime-base/logger.hh | 84 ++++++++++------ src/native/runtime-base/util.hh | 2 +- .../xamarin-debug-app-helper/CMakeLists.txt | 52 ++++++++++ .../debug-app-helper.cc | 76 +++++++------- .../debug-app-helper.hh | 0 11 files changed, 264 insertions(+), 145 deletions(-) create mode 100644 src/native/java-interop/CMakeLists.txt create mode 100644 src/native/xamarin-debug-app-helper/CMakeLists.txt rename src/native/{monodroid/jni => xamarin-debug-app-helper}/debug-app-helper.cc (73%) rename src/native/{monodroid/jni => xamarin-debug-app-helper}/debug-app-helper.hh (100%) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 7a35a5133f8..a001e1e65ef 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -415,5 +415,10 @@ add_link_options("$<$:${COMMON_C_LINKER_ARGS}>") add_subdirectory(libstub) add_subdirectory(libunwind) add_subdirectory(shared) +add_subdirectory(java-interop) add_subdirectory(xamarin-app-stub) add_subdirectory(runtime-base) + +if(DEBUG_BUILD) + add_subdirectory(xamarin-debug-app-helper) +endif() diff --git a/src/native/java-interop/CMakeLists.txt b/src/native/java-interop/CMakeLists.txt new file mode 100644 index 00000000000..e9d59b5bba1 --- /dev/null +++ b/src/native/java-interop/CMakeLists.txt @@ -0,0 +1,45 @@ +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_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/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 1f312c8bf7e..9ee14eed26a 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -256,11 +256,6 @@ 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} ${XA_SHARED_SOURCES} ${SOURCES_DIR}/cpu-arch-detect.cc @@ -451,5 +446,9 @@ target_link_options( target_link_libraries( ${XAMARIN_MONO_ANDROID_LIB} - ${LINK_LIBS} xa::xamarin-app + ${LINK_LIBS} + xa::xamarin-app + xa::shared + xa::runtime-base + xa::java-interop ) diff --git a/src/native/monodroid/jni/debug.cc b/src/native/monodroid/jni/debug.cc index 33f9c0aaa67..54e4e12a3f8 100644 --- a/src/native/monodroid/jni/debug.cc +++ b/src/native/monodroid/jni/debug.cc @@ -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) { diff --git a/src/native/monodroid/jni/debug.hh b/src/native/monodroid/jni/debug.hh index 4eef337b3f0..e7f992d6aa2 100644 --- a/src/native/monodroid/jni/debug.hh +++ b/src/native/monodroid/jni/debug.hh @@ -43,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); @@ -79,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/native/runtime-base/logger.cc b/src/native/runtime-base/logger.cc index db3c4fc47ca..75b7b38711c 100644 --- a/src/native/runtime-base/logger.cc +++ b/src/native/runtime-base/logger.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -10,6 +11,7 @@ #include #include "android-system.hh" +#include "cpp-util.hh" #include "logger.hh" #include "shared-constants.hh" #include "util.hh" @@ -52,46 +54,72 @@ 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; +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 && 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; + } - if (!path) { - Util::create_public_directory (override_dir); - p = Util::path_combine (override_dir, filename); - path = p; - } + unlink (path); - unlink (path); + f = Util::monodroid_fopen (path, "a"); - 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)); + } - 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; } - free (p); - return f; + const char *gref_file = nullptr; + const char *lref_file = nullptr; + bool light_gref = false; + bool light_lref = false; } -static const char *gref_file = nullptr; -static const char *lref_file = nullptr; -static bool light_gref = false; -static bool light_lref = false; +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); +} void -init_reference_logging (const char *override_dir) +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"); @@ -107,8 +135,8 @@ init_reference_logging (const char *override_dir) } } -force_inline static bool -set_category (std::string_view const& name, string_segment& arg, unsigned int entry, bool arg_starts_with_name = false) +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; @@ -123,11 +151,11 @@ set_category (std::string_view const& name, string_segment& arg, unsigned int en } void -init_logging_categories (char*& mono_log_mask, char*& mono_log_level) +Logger::init_logging_categories (char*& mono_log_mask, char*& mono_log_level) noexcept { mono_log_mask = nullptr; mono_log_level = nullptr; - log_timing_categories = LOG_TIMING_DEFAULT; + _log_timing_categories = LogTimingCategories::Default; dynamic_local_string value; if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_LOG_PROPERTY, value) == 0) @@ -212,13 +240,13 @@ init_logging_categories (char*& mono_log_mask, char*& mono_log_level) if (param.starts_with ("timing=fast-bare")) { log_categories |= LOG_TIMING; - log_timing_categories |= LOG_TIMING_FAST_BARE; + _log_timing_categories |= LogTimingCategories::FastBare; continue; } if (param.starts_with ("timing=bare")) { log_categories |= LOG_TIMING; - log_timing_categories |= LOG_TIMING_BARE; + _log_timing_categories |= LogTimingCategories::Bare; continue; } @@ -239,7 +267,7 @@ init_logging_categories (char*& mono_log_mask, char*& mono_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 ()); + set_debugger_log_level (level.get ()); } #endif } diff --git a/src/native/runtime-base/logger.hh b/src/native/runtime-base/logger.hh index 81951615025..ec01000d040 100644 --- a/src/native/runtime-base/logger.hh +++ b/src/native/runtime-base/logger.hh @@ -1,39 +1,67 @@ #ifndef __MONODROID_LOGGER_H__ #define __MONODROID_LOGGER_H__ +#include + #include "java-interop-logger.h" +#include "strings.hh" -void init_logging_categories (char*& mono_log_mask, char*& mono_log_level); +namespace xamarin::android { + enum class LogTimingCategories : uint32_t + { + Default = 0, + Bare = 1 << 0, + FastBare = 1 << 1, + }; -void init_reference_logging (const char *override_dir); + 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; -typedef enum _LogTimingCategories { - LOG_TIMING_DEFAULT = 0, - LOG_TIMING_BARE = 1 << 0, - LOG_TIMING_FAST_BARE = 1 << 1, -} LogTimingCategories; +#if defined(DEBUG) + static void set_debugger_log_level (const char *level) noexcept; -extern unsigned int log_timing_categories; + static bool have_debugger_log_level () noexcept + { + return _got_debugger_log_level; + } -#if DEBUG -extern int gc_spew_enabled; -#endif + static int get_debugger_log_level () noexcept + { + return _debugger_log_level; + } +#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; +#endif // def DEBUG + }; + + // 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 + }; -// 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; + // 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/native/runtime-base/util.hh b/src/native/runtime-base/util.hh index 49c230e5bf0..3901e1f2f72 100644 --- a/src/native/runtime-base/util.hh +++ b/src/native/runtime-base/util.hh @@ -397,7 +397,7 @@ namespace xamarin::android } private: - static char package_property_suffix[9]; + static inline std::array package_property_suffix; static inline int page_size; }; } 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..1a831a1d7a8 --- /dev/null +++ b/src/native/xamarin-debug-app-helper/CMakeLists.txt @@ -0,0 +1,52 @@ +set(LIB_NAME xamarin-debug-app-helper) +set(LIB_ALIAS xa::debug-app-helper) + +set(XAMARIN_APP_SOURCES + debug-app-helper.cc +) + +add_library( + ${LIB_NAME} + SHARED + ${XAMARIN_APP_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_libraries( + ${LIB_NAME} + PRIVATE + xa::shared + xa::xamarin-app + xa::runtime-base + xa::java-interop + -ldl + -llog + -lmonosgen-2.0 +) + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native/monodroid/jni/debug-app-helper.cc b/src/native/xamarin-debug-app-helper/debug-app-helper.cc similarity index 73% rename from src/native/monodroid/jni/debug-app-helper.cc rename to src/native/xamarin-debug-app-helper/debug-app-helper.cc index eb7066b6e62..9bdffa46b76 100644 --- a/src/native/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/native/monodroid/jni/debug-app-helper.hh b/src/native/xamarin-debug-app-helper/debug-app-helper.hh similarity index 100% rename from src/native/monodroid/jni/debug-app-helper.hh rename to src/native/xamarin-debug-app-helper/debug-app-helper.hh From ccfe36ebe6a51e82866b9dd4b1ffa139bd7207bf Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 16 Apr 2024 17:24:03 +0200 Subject: [PATCH 11/49] All libraries are built in their own directories --- src/native/CMakeLists.txt | 14 +- src/native/libunwind/CMakeLists.txt | 17 +- src/native/lz4/CMakeLists.txt | 39 ++ src/native/monodroid/CMakeLists.txt | 391 +++--------------- src/native/monodroid/jni/debug-constants.cc | 4 +- src/native/monodroid/jni/debug.cc | 40 +- .../monodroid/jni/embedded-assemblies-zip.cc | 25 +- .../monodroid/jni/embedded-assemblies.cc | 22 +- src/native/monodroid/jni/globals.hh | 2 - src/native/monodroid/jni/monodroid-glue.cc | 138 +++---- .../monodroid/jni/monodroid-networkinfo.cc | 4 +- src/native/monodroid/jni/osbridge.cc | 23 +- .../monodroid/jni/pinvoke-override-api.cc | 26 +- src/native/monodroid/jni/timezones.cc | 2 +- src/native/monodroid/jni/timing-internal.hh | 11 +- src/native/monodroid/jni/timing.cc | 3 + .../monodroid/jni/xamarin_getifaddrs.cc | 13 +- src/native/runtime-base/logger.cc | 30 +- src/native/runtime-base/logger.hh | 19 +- src/native/runtime-base/util.hh | 4 +- src/native/shared/CMakeLists.txt | 70 ++-- .../{monodroid/jni => shared}/cppcompat.hh | 0 src/native/tracing/CMakeLists.txt | 71 ++++ src/native/tracing/native-tracing.hh | 2 + src/native/xamarin-app-stub/CMakeLists.txt | 6 + .../xamarin-debug-app-helper/CMakeLists.txt | 6 + 26 files changed, 447 insertions(+), 535 deletions(-) create mode 100644 src/native/lz4/CMakeLists.txt rename src/native/{monodroid/jni => shared}/cppcompat.hh (100%) create mode 100644 src/native/tracing/CMakeLists.txt diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index a001e1e65ef..aa890661804 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -25,6 +25,7 @@ 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) @@ -371,6 +372,11 @@ if (ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) ) endif() +set(POTENTIAL_XA_DSO_LINKER_ARGS + -fpic + -fstack-clash-protection +) + unset(SANITIZER_FLAGS) if (ENABLE_CLANG_ASAN) set(SANITIZER_FLAGS -fsanitize=address) @@ -405,6 +411,8 @@ 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}>") @@ -412,13 +420,17 @@ add_compile_options("$<$:${COMMON_C_ARGS}>") add_link_options("$<$:${COMMON_CXX_LINKER_ARGS}>") add_link_options("$<$:${COMMON_C_LINKER_ARGS}>") -add_subdirectory(libstub) 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) diff --git a/src/native/libunwind/CMakeLists.txt b/src/native/libunwind/CMakeLists.txt index cfdb3408d9c..68005783341 100644 --- a/src/native/libunwind/CMakeLists.txt +++ b/src/native/libunwind/CMakeLists.txt @@ -323,13 +323,22 @@ add_library( 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) 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/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 9ee14eed26a..852c8488bd0 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -1,51 +1,5 @@ -cmake_minimum_required(VERSION 3.19) - -# -# MUST be included before project()! -# -include("../../build-tools/cmake/xa_preamble.cmake") - -project( - monodroid - VERSION ${XA_VERSION} - DESCRIPTION "Xamarin.Android native runtime" - HOMEPAGE_URL "https://github.com/xamarin/xamarin-android" - LANGUAGES CXX C -) - -# -# MUST be included after project()! -# -include("../../build-tools/cmake/xa_common.cmake") - option(ENABLE_TIMING "Build with timing support" OFF) -# Environment checks - -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() - -if(NOT DEFINED LIBUNWIND_SOURCE_DIR) - message(FATAL_ERROR "Please set the LIBUNWIND_SOURCE_DIR on command line (-DLIBUNWIND_SOURCE_DIR=path)") -endif() - -if(NOT DEFINED LIBUNWIND_HEADERS_DIR) - message(FATAL_ERROR "Please set the LIBUNWIND_HEADERS_DIR on command line (-DLIBUNWIND_HEADERS_DIR=path)") -endif() - # Needed modules include(CheckIncludeFile) @@ -53,168 +7,10 @@ include(CheckCXXSymbolExists) # Paths -set(SOURCES_DIR ${CMAKE_SOURCE_DIR}/jni) +set(SOURCES_DIR ${CMAKE_SOURCE_DIR}/monodroid/jni) set(BIONIC_SOURCES_DIR "${REPO_ROOT_DIR}/src-ThirdParty/bionic") -set(LZ4_SRC_DIR "${EXTERNAL_DIR}/lz4/lib") -set(LZ4_INCLUDE_DIR ${LZ4_SRC_DIR}) set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") -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 ${LZ4_INCLUDE_DIR}) -include_directories("jni") - - -# Compiler defines - -add_compile_definitions(TSL_NO_EXCEPTIONS) -add_compile_definitions(HAVE_CONFIG_H) -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) - -# 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 @@ -227,7 +23,6 @@ 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 @@ -246,26 +41,16 @@ if(ENABLE_CLANG_UBSAN OR ENABLE_CLANG_ASAN) 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) -set(XAMARIN_NATIVE_TRACING_LIB xamarin-native-tracing) - 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 - ${LZ4_SOURCES} - ${XA_SHARED_SOURCES} - ${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}/jni-remapping.cc - ${SOURCES_DIR}/logger.cc ${SOURCES_DIR}/mono-log-adapter.cc ${SOURCES_DIR}/monodroid-glue.cc ${SOURCES_DIR}/monodroid-networkinfo.cc @@ -274,7 +59,7 @@ set(XAMARIN_MONODROID_SOURCES ${SOURCES_DIR}/osbridge.cc ${SOURCES_DIR}/pinvoke-override-api.cc ${SOURCES_DIR}/runtime-util.cc - ${SOURCES_DIR}/shared-constants.cc + ${SOURCES_DIR}/timing.cc ${SOURCES_DIR}/timezones.cc ${SOURCES_DIR}/timing-internal.cc ${SOURCES_DIR}/xamarin_getifaddrs.cc @@ -289,159 +74,88 @@ endif() if(NOT USES_LIBSTDCPP) list(APPEND XAMARIN_MONODROID_SOURCES ${BIONIC_SOURCES_DIR}/cxa_guard.cc - ${SHARED_SOURCES_DIR}/cxx-abi/string.cc - ${SHARED_SOURCES_DIR}/cxx-abi/terminate.cc ) endif() -set(NATIVE_TRACING_SOURCES - ${SHARED_SOURCES_DIR}/cxx-abi/string.cc -# ${SHARED_SOURCES_DIR}/cxx-abi/terminate.cc - ${TRACING_SOURCES_DIR}/native-tracing.cc - ${XA_SHARED_SOURCES} -) - -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}/shared-constants.cc - ${XA_SHARED_SOURCES} - ) - -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} ) -if(NOT DEBUG_BUILD) - set(CPP_ABI_PATH ${CMAKE_SYSROOT}/usr/lib/${SYSROOT_ABI_LIB_DIR}/${TOOLCHAIN_TRIPLE}/libc++abi.a) - - add_library( - ${XAMARIN_NATIVE_TRACING_LIB} - SHARED ${NATIVE_TRACING_SOURCES} - ) - - target_include_directories( - ${XAMARIN_NATIVE_TRACING_LIB} BEFORE - PRIVATE - ${LIBUNWIND_SOURCE_DIR}/include - ${LIBUNWIND_HEADERS_DIR}/${CMAKE_ANDROID_ARCH_ABI} - ${NDK_CXX_LIBCPPABI_SOURCE_PATH}/include - ) +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 +) - target_compile_options( - ${XAMARIN_NATIVE_TRACING_LIB} +if(DONT_INLINE) + target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} PRIVATE - # Avoid the 'warning: dynamic exception specifications are deprecated' warning from libc++ headers - -Wno-deprecated-dynamic-exception-spec - ${XA_DEFAULT_SYMBOL_VISIBILITY} - # Prevent genration of the .eh_frame section (we don't use exceptions and don't need it) - -fno-asynchronous-unwind-tables - ) - - target_link_options( - ${XAMARIN_NATIVE_TRACING_LIB} - PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} + NO_INLINE ) +endif() - target_link_libraries( - ${XAMARIN_NATIVE_TRACING_LIB} +if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} PRIVATE - -llog - ${CPP_ABI_PATH} - ${XA_LIBRARY_OUTPUT_DIRECTORY}/libunwind_xamarin.a + DEBUG ) +endif() +if (ENABLE_TIMING) target_compile_definitions( - ${XAMARIN_NATIVE_TRACING_LIB} + ${XAMARIN_MONO_ANDROID_LIB} PRIVATE - XAMARIN_TRACING + MONODROID_TIMING ) endif() -# 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}" - ) + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} +) target_include_directories( ${XAMARIN_MONO_ANDROID_LIB} BEFORE PRIVATE - ${LIBUNWIND_SOURCE_DIR}/include - ${LIBUNWIND_HEADERS_DIR}/${CMAKE_ANDROID_ARCH_ABI} + ${CMAKE_CURRENT_BINARY_DIR}/include/ ${CMAKE_SOURCE_DIR}/include + ${EXTERNAL_DIR} + ${ROBIN_MAP_DIR}/include + jni +) + +target_include_directories( + ${XAMARIN_MONO_ANDROID_LIB} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} + ${NATIVE_TRACING_INCLUDE_DIR} + ${LIBUNWIND_INCLUDE_DIRS} ) -set(DEBUG_HELPER_LINK_LIBS "-ldl") +target_link_directories( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + ${NET_RUNTIME_DIR}/native +) target_link_options( ${XAMARIN_MONO_ANDROID_LIB} - PRIVATE ${XA_DEFAULT_SYMBOL_VISIBILITY} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} + ${XA_CXX_DSO_LINKER_ARGS} ) target_link_libraries( @@ -451,4 +165,9 @@ target_link_libraries( xa::shared xa::runtime-base xa::java-interop + xa::lz4 + -lmonosgen-2.0 + -llog ) + +xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) diff --git a/src/native/monodroid/jni/debug-constants.cc b/src/native/monodroid/jni/debug-constants.cc index 82fa9f30008..cf30e8a3621 100644 --- a/src/native/monodroid/jni/debug-constants.cc +++ b/src/native/monodroid/jni/debug-constants.cc @@ -1,8 +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 (Debug::DEBUG_MONO_LOG_PROPERTY.data ()); + return static_cast (SharedConstants::DEBUG_MONO_LOG_PROPERTY.data ()); } diff --git a/src/native/monodroid/jni/debug.cc b/src/native/monodroid/jni/debug.cc index 54e4e12a3f8..b422feacd82 100644 --- a/src/native/monodroid/jni/debug.cc +++ b/src/native/monodroid/jni/debug.cc @@ -74,24 +74,24 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons 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) @@ -140,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; @@ -213,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); @@ -250,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; @@ -260,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; @@ -287,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 } @@ -434,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; } @@ -479,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); } @@ -512,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 @@ -548,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[] = { @@ -574,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/native/monodroid/jni/embedded-assemblies-zip.cc b/src/native/monodroid/jni/embedded-assemblies-zip.cc index b2631fe8b19..d8cf63b31fa 100644 --- a/src/native/monodroid/jni/embedded-assemblies-zip.cc +++ b/src/native/monodroid/jni/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/native/monodroid/jni/embedded-assemblies.cc b/src/native/monodroid/jni/embedded-assemblies.cc index f9119817818..a93f4f9ef5b 100644 --- a/src/native/monodroid/jni/embedded-assemblies.cc +++ b/src/native/monodroid/jni/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; @@ -1128,7 +1128,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 +1211,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 +1359,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 +1368,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/native/monodroid/jni/globals.hh b/src/native/monodroid/jni/globals.hh index 67d482acea1..7717ec2ec79 100644 --- a/src/native/monodroid/jni/globals.hh +++ b/src/native/monodroid/jni/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/native/monodroid/jni/monodroid-glue.cc b/src/native/monodroid/jni/monodroid-glue.cc index 53fbdc7b721..79fbbed84f1 100644 --- a/src/native/monodroid/jni/monodroid-glue.cc +++ b/src/native/monodroid/jni/monodroid-glue.cc @@ -171,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) { @@ -205,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; @@ -228,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; @@ -245,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; } @@ -258,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; } @@ -276,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; } @@ -379,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); @@ -392,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:" }; @@ -411,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; } } @@ -457,7 +457,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_stringhost = host; options->sdb_port = static_cast(sdb_port); @@ -525,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); @@ -671,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++) @@ -743,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], @@ -765,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; } } @@ -875,7 +875,7 @@ 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); @@ -885,7 +885,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec 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; @@ -912,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) { @@ -973,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 ()); } @@ -996,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; } } @@ -1033,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) { @@ -1078,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 */); } @@ -1109,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) { @@ -1131,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 */); } @@ -1161,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); @@ -1174,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)); } @@ -1185,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 ()) { @@ -1214,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) { @@ -1254,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 ()); @@ -1268,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); @@ -1317,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 @@ -1372,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); @@ -1450,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); @@ -1569,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]] { @@ -1605,28 +1605,28 @@ 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 = RuntimeUtil::get_class_from_runtime_field (env, klass, "java_util_TimeZone", true); - utils.monodroid_store_package_name (application_config.android_package_name); + Util::monodroid_store_package_name (application_config.android_package_name); 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 (); @@ -1647,11 +1647,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 (); @@ -1665,8 +1665,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 { @@ -1677,7 +1677,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"); @@ -1686,7 +1686,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]] { @@ -1710,7 +1710,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 Android version: %s (%s; %s); built on %s; NDK version: %s; API level: %s; MonoVM version: %s", diff --git a/src/native/monodroid/jni/monodroid-networkinfo.cc b/src/native/monodroid/jni/monodroid-networkinfo.cc index a2aec751339..e14aa71309e 100644 --- a/src/native/monodroid/jni/monodroid-networkinfo.cc +++ b/src/native/monodroid/jni/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; diff --git a/src/native/monodroid/jni/osbridge.cc b/src/native/monodroid/jni/osbridge.cc index 50e3d560b92..e4c268ba63b 100644 --- a/src/native/monodroid/jni/osbridge.cc +++ b/src/native/monodroid/jni/osbridge.cc @@ -17,6 +17,7 @@ #include "globals.hh" #include "osbridge.hh" +#include "runtime-util.hh" using namespace xamarin::android; using namespace xamarin::android::internal; @@ -653,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 @@ -685,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); @@ -922,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), @@ -966,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); @@ -982,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); } @@ -1006,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; @@ -1066,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; @@ -1101,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!"); } @@ -1115,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/native/monodroid/jni/pinvoke-override-api.cc b/src/native/monodroid/jni/pinvoke-override-api.cc index 09710484807..a83c544a074 100644 --- a/src/native/monodroid/jni/pinvoke-override-api.cc +++ b/src/native/monodroid/jni/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; @@ -270,19 +270,19 @@ monodroid_TypeManager_get_java_class_name (jclass klass) static void monodroid_store_package_name (const char *name) { - utils.monodroid_store_package_name (name); + Util::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 +290,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 +298,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* diff --git a/src/native/monodroid/jni/timezones.cc b/src/native/monodroid/jni/timezones.cc index f5179350ed9..2680af72a2f 100644 --- a/src/native/monodroid/jni/timezones.cc +++ b/src/native/monodroid/jni/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/native/monodroid/jni/timing-internal.hh b/src/native/monodroid/jni/timing-internal.hh index 47417123f27..519b98cb28e 100644 --- a/src/native/monodroid/jni/timing-internal.hh +++ b/src/native/monodroid/jni/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/jni/timing.cc b/src/native/monodroid/jni/timing.cc index ec48972850b..023b16271ec 100644 --- a/src/native/monodroid/jni/timing.cc +++ b/src/native/monodroid/jni/timing.cc @@ -1,5 +1,8 @@ #include "timing-internal.hh" +using namespace xamarin::android; +using namespace xamarin::android::internal; + void timing_point::mark () { FastTiming::get_time (sec, ns); diff --git a/src/native/monodroid/jni/xamarin_getifaddrs.cc b/src/native/monodroid/jni/xamarin_getifaddrs.cc index 9918bde5fa7..211e250763f 100644 --- a/src/native/monodroid/jni/xamarin_getifaddrs.cc +++ b/src/native/monodroid/jni/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. @@ -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]); @@ -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/native/runtime-base/logger.cc b/src/native/runtime-base/logger.cc index 75b7b38711c..0b62f3c87b8 100644 --- a/src/native/runtime-base/logger.cc +++ b/src/native/runtime-base/logger.cc @@ -51,8 +51,6 @@ static constexpr std::array log_names = { #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; namespace { FILE* @@ -95,6 +93,7 @@ namespace { bool light_lref = false; } +#if defined(DEBUG) void Logger::set_debugger_log_level (const char *level) noexcept { @@ -117,6 +116,7 @@ Logger::set_debugger_log_level (const char *level) noexcept _got_debugger_log_level = true; _debugger_log_level = static_cast(v); } +#endif // def DEBUG void Logger::init_reference_logging (const char *override_dir) noexcept @@ -274,7 +274,7 @@ Logger::init_logging_categories (char*& mono_log_mask, char*& mono_log_level) no #if DEBUG if ((log_categories & LOG_GC) != 0) - gc_spew_enabled = 1; + _gc_spew_enabled = 1; #endif /* DEBUG */ } @@ -341,17 +341,19 @@ static constexpr android_LogPriority loglevel_map[] = { 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; +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]; - } + if (map_index > loglevel_map_max_index) { + priority = DEFAULT_PRIORITY; + } else { + priority = loglevel_map[map_index]; + } - __android_log_write (priority, CATEGORY_NAME (category), message); + __android_log_write (priority, CATEGORY_NAME (category), message); + } } diff --git a/src/native/runtime-base/logger.hh b/src/native/runtime-base/logger.hh index ec01000d040..6a477f1a4c7 100644 --- a/src/native/runtime-base/logger.hh +++ b/src/native/runtime-base/logger.hh @@ -20,6 +20,11 @@ namespace xamarin::android { 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; @@ -32,6 +37,16 @@ namespace xamarin::android { { 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: @@ -42,7 +57,7 @@ namespace xamarin::android { #if defined(DEBUG) static inline bool _got_debugger_log_level = false; static inline int _debugger_log_level = 0; - static inline int _gc_spew_enabled; + static inline int _gc_spew_enabled = 0; #endif // def DEBUG }; @@ -64,4 +79,6 @@ namespace xamarin::android { // 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 diff --git a/src/native/runtime-base/util.hh b/src/native/runtime-base/util.hh index 3901e1f2f72..87b03319d4b 100644 --- a/src/native/runtime-base/util.hh +++ b/src/native/runtime-base/util.hh @@ -165,12 +165,12 @@ namespace xamarin::android } template - static bool ends_with (internal::dynamic_local_string& str, std::string_view const& sv) noexcept + static bool ends_with (internal::dynamic_local_string const& str, std::string_view const& sv) noexcept { return ends_with(static_cast const&>(str), sv); } - bool ends_with (const char *str, std::string_view const& sv) const noexcept + static bool ends_with (const char *str, std::string_view const& sv) noexcept { size_t len = strlen (str); if (len < sv.length ()) { diff --git a/src/native/shared/CMakeLists.txt b/src/native/shared/CMakeLists.txt index 0dcfce8bbe3..23f3fe105b3 100644 --- a/src/native/shared/CMakeLists.txt +++ b/src/native/shared/CMakeLists.txt @@ -1,9 +1,15 @@ set(LIB_NAME xa-shared-bits) set(LIB_ALIAS xa::shared) -set(XA_SHARED_SOURCES +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 new_delete.cc ) @@ -15,36 +21,48 @@ add_library( ${LIB_NAME} STATIC ${XA_SHARED_SOURCES} + ${XA_SHARED_CXX_ABI_SOURCES} ) - add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) -target_include_directories( - ${LIB_NAME} - PUBLIC - "$" - "$" - "$" - "$" +add_library( + ${LIB_NAME_NO_ABI} + STATIC + ${XA_SHARED_SOURCES} ) +add_library(${LIB_ALIAS_NO_ABI} ALIAS ${LIB_NAME_NO_ABI}) -target_include_directories( - ${LIB_NAME} - SYSTEM PRIVATE - ${SYSROOT_CXX_INCLUDE_DIR} - ${MONO_RUNTIME_INCLUDE_DIR} -) +macro(lib_target_options TARGET_NAME) + target_include_directories( + ${TARGET_NAME} + PUBLIC + "$" + "$" + "$" + "$" + ) -target_compile_options( - ${LIB_NAME} - PRIVATE - ${XA_COMMON_CXX_ARGS} -) + target_include_directories( + ${TARGET_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} + ) -set_target_properties( - ${LIB_NAME} - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_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() -xa_add_compile_definitions(${LIB_NAME}) +lib_target_options(${LIB_NAME}) +lib_target_options(${LIB_NAME_NO_ABI}) diff --git a/src/native/monodroid/jni/cppcompat.hh b/src/native/shared/cppcompat.hh similarity index 100% rename from src/native/monodroid/jni/cppcompat.hh rename to src/native/shared/cppcompat.hh diff --git a/src/native/tracing/CMakeLists.txt b/src/native/tracing/CMakeLists.txt new file mode 100644 index 00000000000..1b5ac0f4c03 --- /dev/null +++ b/src/native/tracing/CMakeLists.txt @@ -0,0 +1,71 @@ +set(LIB_NAME xamarin-native-tracing) +set(LIB_ALIAS xa::native-tracing) + +set(NATIVE_TRACING_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) + +set(XAMARIN_TRACING_SOURCES + native-tracing.cc +) + +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_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.hh b/src/native/tracing/native-tracing.hh index 6f08e7273b3..f10697ae666 100644 --- a/src/native/tracing/native-tracing.hh +++ b/src/native/tracing/native-tracing.hh @@ -5,7 +5,9 @@ #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 diff --git a/src/native/xamarin-app-stub/CMakeLists.txt b/src/native/xamarin-app-stub/CMakeLists.txt index ff40ebcc227..d04dd98348b 100644 --- a/src/native/xamarin-app-stub/CMakeLists.txt +++ b/src/native/xamarin-app-stub/CMakeLists.txt @@ -32,6 +32,12 @@ target_compile_options( ${XA_COMMON_CXX_ARGS} ) +target_link_options( + ${LIB_NAME} + PRIVATE + ${XA_CXX_DSO_LINKER_ARGS} +) + target_link_libraries( ${LIB_NAME} PRIVATE diff --git a/src/native/xamarin-debug-app-helper/CMakeLists.txt b/src/native/xamarin-debug-app-helper/CMakeLists.txt index 1a831a1d7a8..a6bc43a05ba 100644 --- a/src/native/xamarin-debug-app-helper/CMakeLists.txt +++ b/src/native/xamarin-debug-app-helper/CMakeLists.txt @@ -37,6 +37,12 @@ target_link_directories( ${NET_RUNTIME_DIR}/native ) +target_link_options( + ${LIB_NAME} + PRIVATE + ${XA_CXX_DSO_LINKER_ARGS} +) + target_link_libraries( ${LIB_NAME} PRIVATE From c45283bd6d9adfdc70fd461288940bef0d02c0a0 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 17 Apr 2024 11:20:54 +0200 Subject: [PATCH 12/49] Should fully build now --- src/native/libunwind/CMakeLists.txt | 6 +----- src/native/monodroid/CMakeLists.txt | 2 +- src/native/tracing/CMakeLists.txt | 5 +++-- src/native/xamarin-app-stub/CMakeLists.txt | 12 ++++++++++-- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/native/libunwind/CMakeLists.txt b/src/native/libunwind/CMakeLists.txt index 68005783341..286bf7dabc5 100644 --- a/src/native/libunwind/CMakeLists.txt +++ b/src/native/libunwind/CMakeLists.txt @@ -1,5 +1,5 @@ ensure_variable_set(LIBUNWIND_SOURCE_DIR) -set(LIB_NAME unwind-xamarin) +set(LIB_NAME unwind_xamarin) set(LIB_ALIAS xa::unwind) # @@ -335,10 +335,6 @@ target_include_directories( ${LIB_NAME} PUBLIC "$" - # "$" - # "$" - # "$" - # "$" ) if(TARGET_ARM) diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 852c8488bd0..7f0706ef161 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -141,7 +141,7 @@ target_include_directories( SYSTEM PRIVATE ${SYSROOT_CXX_INCLUDE_DIR} ${MONO_RUNTIME_INCLUDE_DIR} - ${NATIVE_TRACING_INCLUDE_DIR} + ${NATIVE_TRACING_INCLUDE_DIRS} ${LIBUNWIND_INCLUDE_DIRS} ) diff --git a/src/native/tracing/CMakeLists.txt b/src/native/tracing/CMakeLists.txt index 1b5ac0f4c03..1ff574f5cf7 100644 --- a/src/native/tracing/CMakeLists.txt +++ b/src/native/tracing/CMakeLists.txt @@ -1,7 +1,8 @@ set(LIB_NAME xamarin-native-tracing) set(LIB_ALIAS xa::native-tracing) -set(NATIVE_TRACING_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) +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 @@ -18,7 +19,7 @@ add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) target_include_directories( ${LIB_NAME} PUBLIC - "$" + "$" ) target_include_directories( diff --git a/src/native/xamarin-app-stub/CMakeLists.txt b/src/native/xamarin-app-stub/CMakeLists.txt index d04dd98348b..40715846857 100644 --- a/src/native/xamarin-app-stub/CMakeLists.txt +++ b/src/native/xamarin-app-stub/CMakeLists.txt @@ -13,10 +13,12 @@ add_library( add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) +set(XAMARIN_APP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") +set(XAMARIN_APP_INCLUDE_DIRS "${XAMARIN_APP_INCLUDE_DIRS}" PARENT_SCOPE) target_include_directories( ${LIB_NAME} PUBLIC - "$" + "$" ) target_include_directories( @@ -44,10 +46,16 @@ target_link_libraries( xa::shared ) +if(DEBUG_BUILD) + set(LIB_SUBDIR "Debug") +else() + set(LIB_SUBDIR "Release") +endif() + set_target_properties( ${LIB_NAME} PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIB_SUBDIR}" ) xa_add_compile_definitions(${LIB_NAME}) From 4a317bb83937782843416013b3f71ba590bb5dcc Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 17 Apr 2024 18:09:30 +0200 Subject: [PATCH 13/49] A few more build tweaks, mostly for analyzer builds --- src/native/CMakeLists.txt | 7 + src/native/libunwind/CMakeLists.txt | 2 + src/native/monodroid/CMakeLists.txt | 5 +- src/native/native.targets | 10 ++ src/native/runtime-base/CMakeLists.txt | 2 +- src/native/runtime-base/logger.cc | 113 ----------------- src/native/runtime-base/logger.hh | 29 +---- src/native/shared/CMakeLists.txt | 8 ++ src/native/shared/log_functions.cc | 120 ++++++++++++++++++ src/native/shared/log_types.hh | 35 +++++ src/native/tracing/CMakeLists.txt | 1 + src/native/tracing/native-tracing.cc | 2 +- src/native/xamarin-app-stub/CMakeLists.txt | 3 +- .../xamarin-debug-app-helper/CMakeLists.txt | 3 +- 14 files changed, 193 insertions(+), 147 deletions(-) create mode 100644 src/native/shared/log_functions.cc create mode 100644 src/native/shared/log_types.hh diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index aa890661804..e940659baa1 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -99,6 +99,13 @@ 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 # diff --git a/src/native/libunwind/CMakeLists.txt b/src/native/libunwind/CMakeLists.txt index 286bf7dabc5..3de53d23d34 100644 --- a/src/native/libunwind/CMakeLists.txt +++ b/src/native/libunwind/CMakeLists.txt @@ -55,7 +55,9 @@ list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS -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}") diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 7f0706ef161..5d4bf1f723a 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -155,14 +155,15 @@ 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 - xa::shared + ${SHARED_LIB_NAME} xa::runtime-base xa::java-interop xa::lz4 diff --git a/src/native/native.targets b/src/native/native.targets index 97394fd5c65..67bb4bb46d9 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -8,14 +8,24 @@ <_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'" /> diff --git a/src/native/runtime-base/CMakeLists.txt b/src/native/runtime-base/CMakeLists.txt index a10a50da582..954b15277c3 100644 --- a/src/native/runtime-base/CMakeLists.txt +++ b/src/native/runtime-base/CMakeLists.txt @@ -47,7 +47,7 @@ target_include_directories( target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared + ${SHARED_LIB_NAME} xa::xamarin-app ) diff --git a/src/native/runtime-base/logger.cc b/src/native/runtime-base/logger.cc index 0b62f3c87b8..4f39b25ff6b 100644 --- a/src/native/runtime-base/logger.cc +++ b/src/native/runtime-base/logger.cc @@ -16,42 +16,9 @@ #include "shared-constants.hh" #include "util.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; - namespace { FILE* open_file (LogCategories category, const char *path, const char *override_dir, const char *filename) @@ -277,83 +244,3 @@ Logger::init_logging_categories (char*& mono_log_mask, char*& mono_log_level) no _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; - -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/runtime-base/logger.hh b/src/native/runtime-base/logger.hh index 6a477f1a4c7..2111c628bdd 100644 --- a/src/native/runtime-base/logger.hh +++ b/src/native/runtime-base/logger.hh @@ -3,17 +3,10 @@ #include -#include "java-interop-logger.h" +#include "log_types.hh" #include "strings.hh" namespace xamarin::android { - enum class LogTimingCategories : uint32_t - { - Default = 0, - Bare = 1 << 0, - FastBare = 1 << 1, - }; - class Logger { public: @@ -60,25 +53,5 @@ namespace xamarin::android { static inline int _gc_spew_enabled = 0; #endif // def DEBUG }; - - // 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 diff --git a/src/native/shared/CMakeLists.txt b/src/native/shared/CMakeLists.txt index 23f3fe105b3..4f60ac53c25 100644 --- a/src/native/shared/CMakeLists.txt +++ b/src/native/shared/CMakeLists.txt @@ -11,6 +11,7 @@ set(XA_SHARED_CXX_ABI_SOURCES set(XA_SHARED_SOURCES helpers.cc + log_functions.cc new_delete.cc ) @@ -42,6 +43,13 @@ macro(lib_target_options TARGET_NAME) "$" ) + target_link_libraries( + ${TARGET_NAME} + PUBLIC + xa::java-interop + -llog + ) + target_include_directories( ${TARGET_NAME} SYSTEM PRIVATE 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/native/tracing/CMakeLists.txt b/src/native/tracing/CMakeLists.txt index 1ff574f5cf7..d028f1fd581 100644 --- a/src/native/tracing/CMakeLists.txt +++ b/src/native/tracing/CMakeLists.txt @@ -54,6 +54,7 @@ target_link_directories( target_link_options( ${LIB_NAME} PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} ${XA_CXX_DSO_LINKER_ARGS} ) diff --git a/src/native/tracing/native-tracing.cc b/src/native/tracing/native-tracing.cc index 5b69cda234a..f76983a3ef1 100644 --- a/src/native/tracing/native-tracing.cc +++ b/src/native/tracing/native-tracing.cc @@ -158,7 +158,7 @@ const char* xa_get_java_backtrace (JNIEnv *env) noexcept trace.append ("\n"); } - append_frame_number (trace, i); + append_frame_number (trace, static_cast(i)); trace.append (frame_desc); env->ReleaseStringUTFChars (frame_desc_java, frame_desc); } diff --git a/src/native/xamarin-app-stub/CMakeLists.txt b/src/native/xamarin-app-stub/CMakeLists.txt index 40715846857..fa912688d0e 100644 --- a/src/native/xamarin-app-stub/CMakeLists.txt +++ b/src/native/xamarin-app-stub/CMakeLists.txt @@ -37,13 +37,14 @@ target_compile_options( target_link_options( ${LIB_NAME} PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} ${XA_CXX_DSO_LINKER_ARGS} ) target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared + ${SHARED_LIB_NAME} ) if(DEBUG_BUILD) diff --git a/src/native/xamarin-debug-app-helper/CMakeLists.txt b/src/native/xamarin-debug-app-helper/CMakeLists.txt index a6bc43a05ba..18675eb7a1e 100644 --- a/src/native/xamarin-debug-app-helper/CMakeLists.txt +++ b/src/native/xamarin-debug-app-helper/CMakeLists.txt @@ -40,13 +40,14 @@ target_link_directories( target_link_options( ${LIB_NAME} PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} ${XA_CXX_DSO_LINKER_ARGS} ) target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared + ${SHARED_LIB_NAME} xa::xamarin-app xa::runtime-base xa::java-interop From f09a8392a800445d7cf58d46b21e634b7448248a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 18 Apr 2024 15:50:35 +0200 Subject: [PATCH 14/49] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 33 ++++---- .../BuildReleaseArm64XFormsDotNet.apkdesc | 83 ++++++++++--------- 2 files changed, 61 insertions(+), 55 deletions(-) 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 aa48fb18d6c..b526f27e731 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": 64238 + "Size": 64240 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { "Size": 91590 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5318 + "Size": 5317 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 6543 + "Size": 6539 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 8520 + "Size": 8525 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 566145 + "Size": 570166 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 2545 + "Size": 2544 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 4017 + "Size": 4020 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 2932 + "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": 481952 + "Size": 444392 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3135328 + "Size": 3138768 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 67248 @@ -62,16 +62,19 @@ "Size": 155568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 12696 + "Size": 12984 + }, + "lib/arm64-v8a/libxamarin-native-tracing.so": { + "Size": 424360 }, "META-INF/BNDLTOOL.RSA": { "Size": 1223 }, "META-INF/BNDLTOOL.SF": { - "Size": 3266 + "Size": 3380 }, "META-INF/MANIFEST.MF": { - "Size": 3139 + "Size": 3253 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -98,5 +101,5 @@ "Size": 1904 } }, - "PackageSize": 2738709 + "PackageSize": 2853485 } \ 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 979456f1439..88849656f9a 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,13 +38,13 @@ "Size": 8090 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 72398 + "Size": 72410 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { "Size": 458239 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5318 + "Size": 5317 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 3991 @@ -53,61 +53,61 @@ "Size": 5625 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 11517 + "Size": 11516 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { - "Size": 15409 + "Size": 15411 }, "lib/arm64-v8a/lib_System.Collections.NonGeneric.dll.so": { - "Size": 7436 + "Size": 7441 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { - "Size": 1934 + "Size": 1933 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 2548 + "Size": 2547 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 6082 + "Size": 6081 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 6575 + "Size": 6571 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 1968 + "Size": 1969 }, "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { - "Size": 9057 + "Size": 9060 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 6543 + "Size": 6545 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 2323 + "Size": 2325 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 1931 + "Size": 1930 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { "Size": 11963 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 11184 + "Size": 11183 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { - "Size": 15861 + "Size": 15859 }, "lib/arm64-v8a/lib_System.IO.IsolatedStorage.dll.so": { - "Size": 9893 + "Size": 9902 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 20208 + "Size": 20211 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 164627 + "Size": 164628 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 68134 + "Size": 68041 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { "Size": 22237 @@ -116,49 +116,49 @@ "Size": 3587 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 8561 + "Size": 8563 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 872591 + "Size": 874803 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { "Size": 193451 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { - "Size": 42906 + "Size": 42901 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { "Size": 215939 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 16624 + "Size": 16623 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { "Size": 2701 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 4017 + "Size": 4020 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 1858 + "Size": 1857 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 2478 + "Size": 2477 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 3751 + "Size": 3750 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 8095 + "Size": 8101 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 161223 + "Size": 161254 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 1753 + "Size": 1752 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 1769 + "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": 481952 + "Size": 444392 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3135328 + "Size": 3138768 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 67248 @@ -257,7 +257,10 @@ "Size": 155568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 118920 + "Size": 119192 + }, + "lib/arm64-v8a/libxamarin-native-tracing.so": { + "Size": 424360 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -410,10 +413,10 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 98298 + "Size": 98412 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -440,7 +443,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98171 + "Size": 98285 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2480,5 +2483,5 @@ "Size": 812848 } }, - "PackageSize": 10267688 + "PackageSize": 10386560 } \ No newline at end of file From fe3200848667a03b93951c4dcd98258dc468c99c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 19 Apr 2024 16:39:54 +0200 Subject: [PATCH 15/49] Fix a handful of tests, plus... ...remove unused p/invoke + associated code (`monodroid_store_package_name`) ...fix endless recursion caused by a typo in `Util::ends_with` overload ...fix p/invoke include generation script ...update p/invoke dispatcher accordingly --- .../scripts/generate-pinvoke-tables.sh | 4 +- .../monodroid/jni/generate-pinvoke-tables.cc | 3 +- src/native/monodroid/jni/monodroid-glue.cc | 2 - .../monodroid/jni/pinvoke-override-api.cc | 6 --- .../monodroid/jni/pinvoke-tables.include | 4 +- src/native/runtime-base/util.cc | 41 ------------------- src/native/runtime-base/util.hh | 14 +++---- src/native/xamarin-app-stub/CMakeLists.txt | 1 - 8 files changed, 9 insertions(+), 66 deletions(-) diff --git a/build-tools/scripts/generate-pinvoke-tables.sh b/build-tools/scripts/generate-pinvoke-tables.sh index a63853f8562..160ce12520b 100755 --- a/build-tools/scripts/generate-pinvoke-tables.sh +++ b/build-tools/scripts/generate-pinvoke-tables.sh @@ -2,14 +2,14 @@ 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/jni" 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" GENERATED_FILE="${TARGET_FILE}.generated" DIFF_FILE="${TARGET_FILE}.diff" EXTERNAL_DIR="${MY_DIR}/../../external/" -NATIVE_DIR="${MY_DIR}/../../src/native" function die() { diff --git a/src/native/monodroid/jni/generate-pinvoke-tables.cc b/src/native/monodroid/jni/generate-pinvoke-tables.cc index c29358d1e5b..54886c5a48d 100644 --- a/src/native/monodroid/jni/generate-pinvoke-tables.cc +++ b/src/native/monodroid/jni/generate-pinvoke-tables.cc @@ -1,7 +1,7 @@ // // To build and run this utility run (on Linux or macOS): // -// ../../../build-tools/scripts/generate-pinvoke-tables.sh +// ../../../../build-tools/scripts/generate-pinvoke-tables.sh // // A reasonable C++20 compiler is required (g++ 10+, clang 11+, on mac it may require XCode 12.5 or newer) // @@ -67,7 +67,6 @@ const std::vector internal_pinvoke_names = { "_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/native/monodroid/jni/monodroid-glue.cc b/src/native/monodroid/jni/monodroid-glue.cc index 79fbbed84f1..bde0d634242 100644 --- a/src/native/monodroid/jni/monodroid-glue.cc +++ b/src/native/monodroid/jni/monodroid-glue.cc @@ -1610,8 +1610,6 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl java_TimeZone = RuntimeUtil::get_class_from_runtime_field (env, klass, "java_util_TimeZone", true); - Util::monodroid_store_package_name (application_config.android_package_name); - jstring_wrapper jstr (env, lang); set_environment_variable ("LANG", jstr); diff --git a/src/native/monodroid/jni/pinvoke-override-api.cc b/src/native/monodroid/jni/pinvoke-override-api.cc index a83c544a074..c020027eb8a 100644 --- a/src/native/monodroid/jni/pinvoke-override-api.cc +++ b/src/native/monodroid/jni/pinvoke-override-api.cc @@ -267,12 +267,6 @@ 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) -{ - Util::monodroid_store_package_name (name); -} - static int monodroid_get_namespaced_system_property (const char *name, char **value) { diff --git a/src/native/monodroid/jni/pinvoke-tables.include b/src/native/monodroid/jni/pinvoke-tables.include index e358a4d848f..b422e0917a6 100644 --- a/src/native/monodroid/jni/pinvoke-tables.include +++ b/src/native/monodroid/jni/pinvoke-tables.include @@ -13,7 +13,6 @@ 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)}, @@ -536,7 +535,6 @@ 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)}, @@ -991,5 +989,5 @@ constexpr hash_t system_io_compression_native_library_hash = 0xafe3142c; constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93625cd; #endif -constexpr size_t internal_pinvokes_count = 50; +constexpr size_t internal_pinvokes_count = 49; constexpr size_t dotnet_pinvokes_count = 428; diff --git a/src/native/runtime-base/util.cc b/src/native/runtime-base/util.cc index a5ff68f04a8..b1de31a6e6d 100644 --- a/src/native/runtime-base/util.cc +++ b/src/native/runtime-base/util.cc @@ -54,47 +54,6 @@ Util::recv_uninterrupted (int fd, void *buf, size_t len) 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) { diff --git a/src/native/runtime-base/util.hh b/src/native/runtime-base/util.hh index 87b03319d4b..0f67ae6d84e 100644 --- a/src/native/runtime-base/util.hh +++ b/src/native/runtime-base/util.hh @@ -58,7 +58,6 @@ namespace xamarin::android return page_size; } - static void monodroid_store_package_name (const char *name); 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); @@ -167,7 +166,11 @@ namespace xamarin::android template static bool ends_with (internal::dynamic_local_string const& str, std::string_view const& sv) noexcept { - return ends_with(static_cast const&>(str), sv); + 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 @@ -384,12 +387,6 @@ namespace xamarin::android } private: - template - static void package_hash_to_hex (IdxType idx); - - template - static void package_hash_to_hex (uint32_t hash, IdxType idx, Indices... indices); - template static constexpr void assert_char_type () { @@ -397,7 +394,6 @@ namespace xamarin::android } private: - static inline std::array package_property_suffix; static inline int page_size; }; } diff --git a/src/native/xamarin-app-stub/CMakeLists.txt b/src/native/xamarin-app-stub/CMakeLists.txt index fa912688d0e..13044940b7a 100644 --- a/src/native/xamarin-app-stub/CMakeLists.txt +++ b/src/native/xamarin-app-stub/CMakeLists.txt @@ -14,7 +14,6 @@ add_library( add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) set(XAMARIN_APP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") -set(XAMARIN_APP_INCLUDE_DIRS "${XAMARIN_APP_INCLUDE_DIRS}" PARENT_SCOPE) target_include_directories( ${LIB_NAME} PUBLIC From ce05433a6873710baafa3c97bfcbd4de0ec129f3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 22 Apr 2024 11:48:59 +0200 Subject: [PATCH 16/49] Don't put the native tracing library in apk by default To include `libxamarin-native-tracing.so`, one has to request it by setting the `$(_AndroidEnableNativeStackTracing)` MSBuild property to `true` --- .../Microsoft.Android.Sdk.AssemblyResolution.targets | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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" /> From ec09869674f1dc02bcc33979b8263898674dc05e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 22 Apr 2024 15:31:51 +0200 Subject: [PATCH 17/49] Update apkdesc + use anonymous namespace --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 19 +++++++---------- .../BuildReleaseArm64XFormsDotNet.apkdesc | 21 ++++++++----------- src/native/monodroid/jni/monodroid-tracing.cc | 16 +++++++------- 3 files changed, 25 insertions(+), 31 deletions(-) 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 b526f27e731..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,13 +11,13 @@ "Size": 1027 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 64240 + "Size": 64231 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { "Size": 91590 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5317 + "Size": 5315 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 6539 @@ -44,7 +44,7 @@ "Size": 87352 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 444392 + "Size": 476432 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3138768 @@ -62,19 +62,16 @@ "Size": 155568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 12984 - }, - "lib/arm64-v8a/libxamarin-native-tracing.so": { - "Size": 424360 + "Size": 12696 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 3380 + "Size": 3266 }, "META-INF/MANIFEST.MF": { - "Size": 3253 + "Size": 3139 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -101,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 2853485 + "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 88849656f9a..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,13 +38,13 @@ "Size": 8090 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 72410 + "Size": 72406 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 458239 + "Size": 458238 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5317 + "Size": 5315 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 3991 @@ -239,7 +239,7 @@ "Size": 87352 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 444392 + "Size": 476432 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3138768 @@ -257,10 +257,7 @@ "Size": 155568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 119192 - }, - "lib/arm64-v8a/libxamarin-native-tracing.so": { - "Size": 424360 + "Size": 118920 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -413,10 +410,10 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { - "Size": 98412 + "Size": 98298 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -443,7 +440,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98285 + "Size": 98171 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2483,5 +2480,5 @@ "Size": 812848 } }, - "PackageSize": 10386560 + "PackageSize": 10271784 } \ No newline at end of file diff --git a/src/native/monodroid/jni/monodroid-tracing.cc b/src/native/monodroid/jni/monodroid-tracing.cc index 7f85117ae27..e5d0771d49b 100644 --- a/src/native/monodroid/jni/monodroid-tracing.cc +++ b/src/native/monodroid/jni/monodroid-tracing.cc @@ -5,18 +5,18 @@ #include "mono/utils/details/mono-dl-fallback-types.h" #include "monodroid-glue-internal.hh" #include "native-tracing.hh" -#include "cppcompat.hh" #include using namespace xamarin::android::internal; -static decltype(xa_get_native_backtrace)* _xa_get_native_backtrace; -static decltype(xa_get_managed_backtrace)* _xa_get_managed_backtrace; -static decltype(xa_get_java_backtrace)* _xa_get_java_backtrace; -static decltype(xa_get_interesting_signal_handlers)* _xa_get_interesting_signal_handlers; -static bool tracing_init_done; - -static std::mutex tracing_init_lock {}; +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 From e4a8eff978ec9c71c7460c86aec0d797613f5208 Mon Sep 17 00:00:00 2001 From: Peter Collins Date: Mon, 22 Apr 2024 08:41:23 -0700 Subject: [PATCH 18/49] Update policheck/source.gdnsuppress --- .gdn/policheck/source.gdnsuppress | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) 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" From e1c3c8fcd0dfa4cb6a692fe151c9e6ce9391a7fc Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 22 Apr 2024 17:07:46 +0200 Subject: [PATCH 19/49] Drop use of some macros Using `std::source_location` we can now report on, well, source location without having to resort to C macros. --- src/native/monodroid/jni/debug.cc | 2 +- .../monodroid/jni/embedded-assemblies.cc | 5 ++--- .../monodroid/jni/monodroid-networkinfo.cc | 2 +- .../monodroid/jni/xamarin_getifaddrs.cc | 4 ++-- src/native/runtime-base/android-system.cc | 10 ++++----- src/native/runtime-base/strings.hh | 8 +++---- src/native/runtime-base/util.cc | 6 +++--- src/native/runtime-base/util.hh | 2 +- src/native/shared/cpp-util.hh | 11 ++++++---- src/native/shared/helpers.cc | 12 ++++++++++- src/native/shared/helpers.hh | 21 +++++++++++-------- 11 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/native/monodroid/jni/debug.cc b/src/native/monodroid/jni/debug.cc index b422feacd82..7397fece427 100644 --- a/src/native/monodroid/jni/debug.cc +++ b/src/native/monodroid/jni/debug.cc @@ -69,7 +69,7 @@ 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; diff --git a/src/native/monodroid/jni/embedded-assemblies.cc b/src/native/monodroid/jni/embedded-assemblies.cc index a93f4f9ef5b..07eddf61114 100644 --- a/src/native/monodroid/jni/embedded-assemblies.cc +++ b/src/native/monodroid/jni/embedded-assemblies.cc @@ -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 ); diff --git a/src/native/monodroid/jni/monodroid-networkinfo.cc b/src/native/monodroid/jni/monodroid-networkinfo.cc index e14aa71309e..50267299def 100644 --- a/src/native/monodroid/jni/monodroid-networkinfo.cc +++ b/src/native/monodroid/jni/monodroid-networkinfo.cc @@ -167,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/jni/xamarin_getifaddrs.cc b/src/native/monodroid/jni/xamarin_getifaddrs.cc index 211e250763f..d2dab9643eb 100644 --- a/src/native/monodroid/jni/xamarin_getifaddrs.cc +++ b/src/native/monodroid/jni/xamarin_getifaddrs.cc @@ -531,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) { @@ -879,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; diff --git a/src/native/runtime-base/android-system.cc b/src/native/runtime-base/android-system.cc index c6643b7e19f..cdc73976dd9 100644 --- a/src/native/runtime-base/android-system.cc +++ b/src/native/runtime-base/android-system.cc @@ -107,7 +107,7 @@ AndroidSystem::add_system_property (const char *name, const char *value) noexcep } 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; @@ -137,7 +137,7 @@ AndroidSystem::_monodroid__system_property_get (const char *name, char *sp_value 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]; } @@ -168,7 +168,7 @@ 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 @@ -191,7 +191,7 @@ AndroidSystem::monodroid_get_system_property (const char *name, char **value) no } 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; @@ -225,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); diff --git a/src/native/runtime-base/strings.hh b/src/native/runtime-base/strings.hh index 97f22e0b805..a552abd345c 100644 --- a/src/native/runtime-base/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/native/runtime-base/util.cc b/src/native/runtime-base/util.cc index b1de31a6e6d..892d7fe5343 100644 --- a/src/native/runtime-base/util.cc +++ b/src/native/runtime-base/util.cc @@ -124,7 +124,7 @@ Util::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'; @@ -341,7 +341,7 @@ Util::monodroid_strsplit (const char *str, const char *delimiter, size_t max_tok 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)) { @@ -363,7 +363,7 @@ Util::monodroid_strsplit (const char *str, const char *delimiter, size_t max_tok } 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'; diff --git a/src/native/runtime-base/util.hh b/src/native/runtime-base/util.hh index 0f67ae6d84e..718e2e87551 100644 --- a/src/native/runtime-base/util.hh +++ b/src/native/runtime-base/util.hh @@ -281,7 +281,7 @@ namespace xamarin::android return nullptr; } - size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, len, 1); + size_t alloc_size = Helpers::add_with_overflow_check (len, 1); auto ret = new char[alloc_size]; memcpy (ret, s, len); ret[len] = '\0'; diff --git a/src/native/shared/cpp-util.hh b/src/native/shared/cpp-util.hh index 66dddc1d325..3ac87f9de82 100644 --- a/src/native/shared/cpp-util.hh +++ b/src/native/shared/cpp-util.hh @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -33,10 +34,12 @@ 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 { diff --git a/src/native/shared/helpers.cc b/src/native/shared/helpers.cc index e3103c04597..5ccd7bd4e3f 100644 --- a/src/native/shared/helpers.cc +++ b/src/native/shared/helpers.cc @@ -3,7 +3,17 @@ using namespace xamarin::android; [[noreturn]] void -Helpers::abort_application () noexcept +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 index 40eff78eaca..ea758799dd3 100644 --- a/src/native/shared/helpers.hh +++ b/src/native/shared/helpers.hh @@ -3,26 +3,28 @@ #include #include +#include #include #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__)) +// #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 [[gnu::visibility("hidden")]] Helpers { public: template - force_inline static Ret add_with_overflow_check (const char *file, uint32_t line, P1 a, P2 b) noexcept + 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", file, line); - abort_application (); + log_fatal (LOG_DEFAULT, "Integer overflow on addition at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (DoNotLogLocation); } return ret; @@ -40,19 +42,20 @@ namespace xamarin::android // fail // template - force_inline static Ret multiply_with_overflow_check (const char *file, uint32_t line, size_t a, size_t b) noexcept + force_inline static Ret multiply_with_overflow_check (size_t a, size_t 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", file, line); - abort_application (); + log_fatal (LOG_DEFAULT, "Integer overflow on multiplication at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (DoNotLogLocation); } return ret; } - [[noreturn]] static void abort_application () noexcept; + [[noreturn]] static void abort_application (bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; }; } #endif // __HELPERS_HH From 8986fc2b23cd3d27c31da8073915df63bf3929d0 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 22 Apr 2024 17:21:35 +0200 Subject: [PATCH 20/49] Cleanup --- src/native/shared/helpers.hh | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/native/shared/helpers.hh b/src/native/shared/helpers.hh index ea758799dd3..ba576d0fef2 100644 --- a/src/native/shared/helpers.hh +++ b/src/native/shared/helpers.hh @@ -1,7 +1,6 @@ #ifndef __HELPERS_HH #define __HELPERS_HH -#include #include #include @@ -10,9 +9,6 @@ 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 [[gnu::visibility("hidden")]] Helpers { public: @@ -24,32 +20,21 @@ namespace xamarin::android 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); + abort_application (DoNotLogLocation, sloc); } 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 (size_t a, size_t b, std::source_location sloc = std::source_location::current ()) noexcept + 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); + abort_application (DoNotLogLocation, sloc); } return ret; From 48cb44df72d8e92d005c8dc7e5a9852205b4ea35 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 23 Apr 2024 16:46:28 +0200 Subject: [PATCH 21/49] Hopefully final cleanup steps --- Configuration.props | 2 + .../scripts/generate-pinvoke-tables.sh | 2 +- src/native/.gitignore | 1 + src/native/CMakeLists.txt | 20 ++ src/native/java-interop/CMakeLists.txt | 1 + src/native/monodroid/.gitignore | 4 + src/native/monodroid/CMakeLists.txt | 50 ++-- src/native/monodroid/{jni => }/build-info.hh | 0 src/native/monodroid/{jni => }/config.h | 0 src/native/monodroid/config.xml | 41 --- .../monodroid/{jni => }/debug-constants.cc | 0 src/native/monodroid/{jni => }/debug.cc | 0 src/native/monodroid/{jni => }/debug.hh | 0 .../{jni => }/designer-assemblies.cc | 0 .../{jni => }/designer-assemblies.hh | 0 .../{jni => }/embedded-assemblies-zip.cc | 0 .../{jni => }/embedded-assemblies.cc | 0 .../{jni => }/embedded-assemblies.hh | 0 .../{jni => }/generate-pinvoke-tables.cc | 2 +- src/native/monodroid/{jni => }/globals.cc | 0 src/native/monodroid/{jni => }/globals.hh | 0 .../monodroid/{jni => }/host-config.h.in | 0 .../{jni => }/internal-pinvoke-api.cc | 0 .../monodroid/{jni => }/jni-remapping.cc | 0 .../monodroid/{jni => }/jni-remapping.hh | 0 src/native/monodroid/jni/.gitignore | 7 - src/native/monodroid/jni/TODO.md | 11 - src/native/monodroid/machine.config.xml | 150 ---------- .../monodroid/{jni => }/mono-image-loader.hh | 0 .../monodroid/{jni => }/mono-log-adapter.cc | 0 .../{jni => }/mono_android_Runtime.h | 0 .../{jni => }/monodroid-glue-designer.cc | 0 .../{jni => }/monodroid-glue-internal.hh | 0 .../monodroid/{jni => }/monodroid-glue.cc | 0 .../monodroid/{jni => }/monodroid-glue.hh | 0 .../{jni => }/monodroid-networkinfo.cc | 0 .../monodroid/{jni => }/monodroid-tracing.cc | 0 src/native/monodroid/monodroid.csproj | 22 -- src/native/monodroid/{jni => }/monodroid.h | 0 src/native/monodroid/monodroid.targets | 278 ------------------ src/native/monodroid/{jni => }/monodroid.x | Bin .../monodroid/{jni => }/monovm-properties.cc | 0 .../monodroid/{jni => }/monovm-properties.hh | 0 src/native/monodroid/{jni => }/osbridge.cc | 0 src/native/monodroid/{jni => }/osbridge.hh | 0 .../{jni => }/pinvoke-override-api.cc | 0 .../{jni => }/pinvoke-tables.include | 0 .../monodroid/{jni => }/runtime-util.cc | 0 .../monodroid/{jni => }/runtime-util.hh | 0 src/native/monodroid/{jni => }/search.hh | 0 .../monodroid/{jni => }/startup-aware-lock.hh | 0 src/native/monodroid/{jni => }/timezones.cc | 0 .../monodroid/{jni => }/timing-internal.cc | 0 .../monodroid/{jni => }/timing-internal.hh | 0 src/native/monodroid/{jni => }/timing.cc | 0 src/native/monodroid/{jni => }/timing.hh | 0 src/native/monodroid/{jni => }/win32/jni_md.h | 0 .../{jni => }/xa-internal-api-impl.hh | 0 .../monodroid/{jni => }/xa-internal-api.cc | 0 .../monodroid/{jni => }/xa-internal-api.hh | 0 .../{jni => }/xamarin-android-app-context.cc | 0 .../monodroid/{jni => }/xamarin_getifaddrs.cc | 0 .../monodroid/{jni => }/xamarin_getifaddrs.h | 0 src/native/native.targets | 28 +- src/native/runtime-base/CMakeLists.txt | 1 + src/native/shared/CMakeLists.txt | 1 + src/native/tracing/CMakeLists.txt | 1 + .../xamarin-debug-app-helper/CMakeLists.txt | 5 +- 68 files changed, 91 insertions(+), 536 deletions(-) rename src/native/monodroid/{jni => }/build-info.hh (100%) rename src/native/monodroid/{jni => }/config.h (100%) delete mode 100644 src/native/monodroid/config.xml rename src/native/monodroid/{jni => }/debug-constants.cc (100%) rename src/native/monodroid/{jni => }/debug.cc (100%) rename src/native/monodroid/{jni => }/debug.hh (100%) rename src/native/monodroid/{jni => }/designer-assemblies.cc (100%) rename src/native/monodroid/{jni => }/designer-assemblies.hh (100%) rename src/native/monodroid/{jni => }/embedded-assemblies-zip.cc (100%) rename src/native/monodroid/{jni => }/embedded-assemblies.cc (100%) rename src/native/monodroid/{jni => }/embedded-assemblies.hh (100%) rename src/native/monodroid/{jni => }/generate-pinvoke-tables.cc (99%) rename src/native/monodroid/{jni => }/globals.cc (100%) rename src/native/monodroid/{jni => }/globals.hh (100%) rename src/native/monodroid/{jni => }/host-config.h.in (100%) rename src/native/monodroid/{jni => }/internal-pinvoke-api.cc (100%) rename src/native/monodroid/{jni => }/jni-remapping.cc (100%) rename src/native/monodroid/{jni => }/jni-remapping.hh (100%) delete mode 100644 src/native/monodroid/jni/.gitignore delete mode 100644 src/native/monodroid/jni/TODO.md delete mode 100644 src/native/monodroid/machine.config.xml rename src/native/monodroid/{jni => }/mono-image-loader.hh (100%) rename src/native/monodroid/{jni => }/mono-log-adapter.cc (100%) rename src/native/monodroid/{jni => }/mono_android_Runtime.h (100%) rename src/native/monodroid/{jni => }/monodroid-glue-designer.cc (100%) rename src/native/monodroid/{jni => }/monodroid-glue-internal.hh (100%) rename src/native/monodroid/{jni => }/monodroid-glue.cc (100%) rename src/native/monodroid/{jni => }/monodroid-glue.hh (100%) rename src/native/monodroid/{jni => }/monodroid-networkinfo.cc (100%) rename src/native/monodroid/{jni => }/monodroid-tracing.cc (100%) delete mode 100644 src/native/monodroid/monodroid.csproj rename src/native/monodroid/{jni => }/monodroid.h (100%) delete mode 100644 src/native/monodroid/monodroid.targets rename src/native/monodroid/{jni => }/monodroid.x (100%) rename src/native/monodroid/{jni => }/monovm-properties.cc (100%) rename src/native/monodroid/{jni => }/monovm-properties.hh (100%) rename src/native/monodroid/{jni => }/osbridge.cc (100%) rename src/native/monodroid/{jni => }/osbridge.hh (100%) rename src/native/monodroid/{jni => }/pinvoke-override-api.cc (100%) rename src/native/monodroid/{jni => }/pinvoke-tables.include (100%) rename src/native/monodroid/{jni => }/runtime-util.cc (100%) rename src/native/monodroid/{jni => }/runtime-util.hh (100%) rename src/native/monodroid/{jni => }/search.hh (100%) rename src/native/monodroid/{jni => }/startup-aware-lock.hh (100%) rename src/native/monodroid/{jni => }/timezones.cc (100%) rename src/native/monodroid/{jni => }/timing-internal.cc (100%) rename src/native/monodroid/{jni => }/timing-internal.hh (100%) rename src/native/monodroid/{jni => }/timing.cc (100%) rename src/native/monodroid/{jni => }/timing.hh (100%) rename src/native/monodroid/{jni => }/win32/jni_md.h (100%) rename src/native/monodroid/{jni => }/xa-internal-api-impl.hh (100%) rename src/native/monodroid/{jni => }/xa-internal-api.cc (100%) rename src/native/monodroid/{jni => }/xa-internal-api.hh (100%) rename src/native/monodroid/{jni => }/xamarin-android-app-context.cc (100%) rename src/native/monodroid/{jni => }/xamarin_getifaddrs.cc (100%) rename src/native/monodroid/{jni => }/xamarin_getifaddrs.h (100%) diff --git a/Configuration.props b/Configuration.props index 68373be4123..522ba39d3a4 100644 --- a/Configuration.props +++ b/Configuration.props @@ -106,6 +106,7 @@ $(MSBuildThisFileDirectory)external\sqlite $(MSBuildThisFileDirectory)external\libunwind $(BootstrapOutputDirectory)\libunwind + $(MSBuildThisFileDirectory)external\lz4 $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)src-ThirdParty\ armeabi-v7a;x86 @@ -148,6 +149,7 @@ $([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/build-tools/scripts/generate-pinvoke-tables.sh b/build-tools/scripts/generate-pinvoke-tables.sh index 160ce12520b..0a7c187168a 100755 --- a/build-tools/scripts/generate-pinvoke-tables.sh +++ b/build-tools/scripts/generate-pinvoke-tables.sh @@ -3,7 +3,7 @@ MY_DIR="$(dirname $0)" HOST="$(uname | tr A-Z a-z)" NATIVE_DIR="${MY_DIR}/../../src/native" -MONODROID_SOURCE_DIR="${NATIVE_DIR}/monodroid/jni" +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" diff --git a/src/native/.gitignore b/src/native/.gitignore index 34d21e62347..06af5ee0acd 100644 --- a/src/native/.gitignore +++ b/src/native/.gitignore @@ -1,2 +1,3 @@ CMakeUserPresets.json CMakePresets.json +static-analysis.*.txt diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index e940659baa1..3ed2976b575 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -278,6 +278,19 @@ macro(xa_check_cxx_linker_args VARNAME _CHECK_ARGS) 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 # @@ -441,3 +454,10 @@ if(DEBUG_BUILD) 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/java-interop/CMakeLists.txt b/src/native/java-interop/CMakeLists.txt index e9d59b5bba1..96510c4925f 100644 --- a/src/native/java-interop/CMakeLists.txt +++ b/src/native/java-interop/CMakeLists.txt @@ -8,6 +8,7 @@ set(JAVA_INTEROP_SOURCES ${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} diff --git a/src/native/monodroid/.gitignore b/src/native/monodroid/.gitignore index 76f4fbd0f2d..b794e58ba97 100644 --- a/src/native/monodroid/.gitignore +++ b/src/native/monodroid/.gitignore @@ -1,2 +1,6 @@ libs sources.projitems +pinvoke-tables.include.generated +pinvoke-tables.include.diff +generate-pinvoke-tables +generate-pinvoke-tables.exe diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 5d4bf1f723a..ed27b2429d6 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -7,7 +7,6 @@ include(CheckCXXSymbolExists) # Paths -set(SOURCES_DIR ${CMAKE_SOURCE_DIR}/monodroid/jni) set(BIONIC_SOURCES_DIR "${REPO_ROOT_DIR}/src-ThirdParty/bionic") set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") @@ -45,31 +44,40 @@ 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 - ${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}/jni-remapping.cc - ${SOURCES_DIR}/mono-log-adapter.cc - ${SOURCES_DIR}/monodroid-glue.cc - ${SOURCES_DIR}/monodroid-networkinfo.cc - ${SOURCES_DIR}/monodroid-tracing.cc - ${SOURCES_DIR}/monovm-properties.cc - ${SOURCES_DIR}/osbridge.cc - ${SOURCES_DIR}/pinvoke-override-api.cc - ${SOURCES_DIR}/runtime-util.cc - ${SOURCES_DIR}/timing.cc - ${SOURCES_DIR}/timezones.cc - ${SOURCES_DIR}/timing-internal.cc - ${SOURCES_DIR}/xamarin_getifaddrs.cc + 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 - ${SOURCES_DIR}/xamarin-android-app-context.cc + 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 @@ -78,7 +86,7 @@ if(NOT USES_LIBSTDCPP) endif() # Build -configure_file(jni/host-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/host-config.h) +configure_file(host-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/host-config.h) add_library( ${XAMARIN_MONO_ANDROID_LIB} diff --git a/src/native/monodroid/jni/build-info.hh b/src/native/monodroid/build-info.hh similarity index 100% rename from src/native/monodroid/jni/build-info.hh rename to src/native/monodroid/build-info.hh diff --git a/src/native/monodroid/jni/config.h b/src/native/monodroid/config.h similarity index 100% rename from src/native/monodroid/jni/config.h rename to src/native/monodroid/config.h diff --git a/src/native/monodroid/config.xml b/src/native/monodroid/config.xml deleted file mode 100644 index 5c4917bbfa0..00000000000 --- a/src/native/monodroid/config.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/native/monodroid/jni/debug-constants.cc b/src/native/monodroid/debug-constants.cc similarity index 100% rename from src/native/monodroid/jni/debug-constants.cc rename to src/native/monodroid/debug-constants.cc diff --git a/src/native/monodroid/jni/debug.cc b/src/native/monodroid/debug.cc similarity index 100% rename from src/native/monodroid/jni/debug.cc rename to src/native/monodroid/debug.cc diff --git a/src/native/monodroid/jni/debug.hh b/src/native/monodroid/debug.hh similarity index 100% rename from src/native/monodroid/jni/debug.hh rename to src/native/monodroid/debug.hh diff --git a/src/native/monodroid/jni/designer-assemblies.cc b/src/native/monodroid/designer-assemblies.cc similarity index 100% rename from src/native/monodroid/jni/designer-assemblies.cc rename to src/native/monodroid/designer-assemblies.cc diff --git a/src/native/monodroid/jni/designer-assemblies.hh b/src/native/monodroid/designer-assemblies.hh similarity index 100% rename from src/native/monodroid/jni/designer-assemblies.hh rename to src/native/monodroid/designer-assemblies.hh diff --git a/src/native/monodroid/jni/embedded-assemblies-zip.cc b/src/native/monodroid/embedded-assemblies-zip.cc similarity index 100% rename from src/native/monodroid/jni/embedded-assemblies-zip.cc rename to src/native/monodroid/embedded-assemblies-zip.cc diff --git a/src/native/monodroid/jni/embedded-assemblies.cc b/src/native/monodroid/embedded-assemblies.cc similarity index 100% rename from src/native/monodroid/jni/embedded-assemblies.cc rename to src/native/monodroid/embedded-assemblies.cc diff --git a/src/native/monodroid/jni/embedded-assemblies.hh b/src/native/monodroid/embedded-assemblies.hh similarity index 100% rename from src/native/monodroid/jni/embedded-assemblies.hh rename to src/native/monodroid/embedded-assemblies.hh diff --git a/src/native/monodroid/jni/generate-pinvoke-tables.cc b/src/native/monodroid/generate-pinvoke-tables.cc similarity index 99% rename from src/native/monodroid/jni/generate-pinvoke-tables.cc rename to src/native/monodroid/generate-pinvoke-tables.cc index 54886c5a48d..0c132d5461b 100644 --- a/src/native/monodroid/jni/generate-pinvoke-tables.cc +++ b/src/native/monodroid/generate-pinvoke-tables.cc @@ -1,7 +1,7 @@ // // To build and run this utility run (on Linux or macOS): // -// ../../../../build-tools/scripts/generate-pinvoke-tables.sh +// ../../../build-tools/scripts/generate-pinvoke-tables.sh // // A reasonable C++20 compiler is required (g++ 10+, clang 11+, on mac it may require XCode 12.5 or newer) // diff --git a/src/native/monodroid/jni/globals.cc b/src/native/monodroid/globals.cc similarity index 100% rename from src/native/monodroid/jni/globals.cc rename to src/native/monodroid/globals.cc diff --git a/src/native/monodroid/jni/globals.hh b/src/native/monodroid/globals.hh similarity index 100% rename from src/native/monodroid/jni/globals.hh rename to src/native/monodroid/globals.hh diff --git a/src/native/monodroid/jni/host-config.h.in b/src/native/monodroid/host-config.h.in similarity index 100% rename from src/native/monodroid/jni/host-config.h.in rename to src/native/monodroid/host-config.h.in diff --git a/src/native/monodroid/jni/internal-pinvoke-api.cc b/src/native/monodroid/internal-pinvoke-api.cc similarity index 100% rename from src/native/monodroid/jni/internal-pinvoke-api.cc rename to src/native/monodroid/internal-pinvoke-api.cc diff --git a/src/native/monodroid/jni/jni-remapping.cc b/src/native/monodroid/jni-remapping.cc similarity index 100% rename from src/native/monodroid/jni/jni-remapping.cc rename to src/native/monodroid/jni-remapping.cc diff --git a/src/native/monodroid/jni/jni-remapping.hh b/src/native/monodroid/jni-remapping.hh similarity index 100% rename from src/native/monodroid/jni/jni-remapping.hh rename to src/native/monodroid/jni-remapping.hh diff --git a/src/native/monodroid/jni/.gitignore b/src/native/monodroid/jni/.gitignore deleted file mode 100644 index 7454689c137..00000000000 --- a/src/native/monodroid/jni/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -Application.mk -config.include -machine.config.include -pinvoke-tables.include.generated -pinvoke-tables.include.diff -generate-pinvoke-tables -generate-pinvoke-tables.exe diff --git a/src/native/monodroid/jni/TODO.md b/src/native/monodroid/jni/TODO.md deleted file mode 100644 index 88c1d04ea86..00000000000 --- a/src/native/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/native/monodroid/machine.config.xml b/src/native/monodroid/machine.config.xml deleted file mode 100644 index 485d8b34170..00000000000 --- a/src/native/monodroid/machine.config.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - -
-
-
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/native/monodroid/jni/mono-image-loader.hh b/src/native/monodroid/mono-image-loader.hh similarity index 100% rename from src/native/monodroid/jni/mono-image-loader.hh rename to src/native/monodroid/mono-image-loader.hh diff --git a/src/native/monodroid/jni/mono-log-adapter.cc b/src/native/monodroid/mono-log-adapter.cc similarity index 100% rename from src/native/monodroid/jni/mono-log-adapter.cc rename to src/native/monodroid/mono-log-adapter.cc diff --git a/src/native/monodroid/jni/mono_android_Runtime.h b/src/native/monodroid/mono_android_Runtime.h similarity index 100% rename from src/native/monodroid/jni/mono_android_Runtime.h rename to src/native/monodroid/mono_android_Runtime.h diff --git a/src/native/monodroid/jni/monodroid-glue-designer.cc b/src/native/monodroid/monodroid-glue-designer.cc similarity index 100% rename from src/native/monodroid/jni/monodroid-glue-designer.cc rename to src/native/monodroid/monodroid-glue-designer.cc diff --git a/src/native/monodroid/jni/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh similarity index 100% rename from src/native/monodroid/jni/monodroid-glue-internal.hh rename to src/native/monodroid/monodroid-glue-internal.hh diff --git a/src/native/monodroid/jni/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc similarity index 100% rename from src/native/monodroid/jni/monodroid-glue.cc rename to src/native/monodroid/monodroid-glue.cc diff --git a/src/native/monodroid/jni/monodroid-glue.hh b/src/native/monodroid/monodroid-glue.hh similarity index 100% rename from src/native/monodroid/jni/monodroid-glue.hh rename to src/native/monodroid/monodroid-glue.hh diff --git a/src/native/monodroid/jni/monodroid-networkinfo.cc b/src/native/monodroid/monodroid-networkinfo.cc similarity index 100% rename from src/native/monodroid/jni/monodroid-networkinfo.cc rename to src/native/monodroid/monodroid-networkinfo.cc diff --git a/src/native/monodroid/jni/monodroid-tracing.cc b/src/native/monodroid/monodroid-tracing.cc similarity index 100% rename from src/native/monodroid/jni/monodroid-tracing.cc rename to src/native/monodroid/monodroid-tracing.cc diff --git a/src/native/monodroid/monodroid.csproj b/src/native/monodroid/monodroid.csproj deleted file mode 100644 index 100496fe8fc..00000000000 --- a/src/native/monodroid/monodroid.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - netstandard2.0 - Debug - AnyCPU - Exe - false - - - - - - $(MicrosoftAndroidSdkOutDir)lib\ - - - - - - - - - diff --git a/src/native/monodroid/jni/monodroid.h b/src/native/monodroid/monodroid.h similarity index 100% rename from src/native/monodroid/jni/monodroid.h rename to src/native/monodroid/monodroid.h diff --git a/src/native/monodroid/monodroid.targets b/src/native/monodroid/monodroid.targets deleted file mode 100644 index 7d0c3010bbf..00000000000 --- a/src/native/monodroid/monodroid.targets +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - <_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 - - - - - - - - - - - - - - - - - - - - - - - - - <_ConfigureRuntimesInputs Include="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')" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - - - - - - - - - <_CmakeLibUnwind>-DLIBUNWIND_SOURCE_DIR="$(LibUnwindSourceDirectory)" -DLIBUNWIND_HEADERS_DIR="$(LibUnwindGeneratedHeadersDirectory)" - <_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) - - - - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release - - - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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 - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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 - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - $(_CmakeAndroidFlags) $(_CmakeLibUnwind) -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)" - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release - - - - - - - - - <_MonoDroidSources Include="jni\*.cc;jni\*.h;jni\*.hh;jni\**\*.c;" /> - - - - - - <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> - <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> - <_BuildAndroidRuntimesInputs Include="@(_MonoDroidSources)" /> - <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.debug.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.release.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app.so')" /> - - - <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+ubsan.debug.so')" /> - <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+asan.debug.so')" /> - <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+asan.release.so')" /> - <_BuildAndroidAnalyzerRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-checked+ubsan.release.so')" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_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 - - - - - - - - <_ArmRuntimePackFiles Include="$(OutputPath)\android-arm\*.*" /> - <_Arm64RuntimePackFiles Include="$(OutputPath)\android-arm64\*.*" /> - <_x86RuntimePackFiles Include="$(OutputPath)\android-x86\*.*" /> - <_x64RuntimePackFiles Include="$(OutputPath)\android-x64\*.*" /> - - - - - - - diff --git a/src/native/monodroid/jni/monodroid.x b/src/native/monodroid/monodroid.x similarity index 100% rename from src/native/monodroid/jni/monodroid.x rename to src/native/monodroid/monodroid.x diff --git a/src/native/monodroid/jni/monovm-properties.cc b/src/native/monodroid/monovm-properties.cc similarity index 100% rename from src/native/monodroid/jni/monovm-properties.cc rename to src/native/monodroid/monovm-properties.cc diff --git a/src/native/monodroid/jni/monovm-properties.hh b/src/native/monodroid/monovm-properties.hh similarity index 100% rename from src/native/monodroid/jni/monovm-properties.hh rename to src/native/monodroid/monovm-properties.hh diff --git a/src/native/monodroid/jni/osbridge.cc b/src/native/monodroid/osbridge.cc similarity index 100% rename from src/native/monodroid/jni/osbridge.cc rename to src/native/monodroid/osbridge.cc diff --git a/src/native/monodroid/jni/osbridge.hh b/src/native/monodroid/osbridge.hh similarity index 100% rename from src/native/monodroid/jni/osbridge.hh rename to src/native/monodroid/osbridge.hh diff --git a/src/native/monodroid/jni/pinvoke-override-api.cc b/src/native/monodroid/pinvoke-override-api.cc similarity index 100% rename from src/native/monodroid/jni/pinvoke-override-api.cc rename to src/native/monodroid/pinvoke-override-api.cc diff --git a/src/native/monodroid/jni/pinvoke-tables.include b/src/native/monodroid/pinvoke-tables.include similarity index 100% rename from src/native/monodroid/jni/pinvoke-tables.include rename to src/native/monodroid/pinvoke-tables.include diff --git a/src/native/monodroid/jni/runtime-util.cc b/src/native/monodroid/runtime-util.cc similarity index 100% rename from src/native/monodroid/jni/runtime-util.cc rename to src/native/monodroid/runtime-util.cc diff --git a/src/native/monodroid/jni/runtime-util.hh b/src/native/monodroid/runtime-util.hh similarity index 100% rename from src/native/monodroid/jni/runtime-util.hh rename to src/native/monodroid/runtime-util.hh diff --git a/src/native/monodroid/jni/search.hh b/src/native/monodroid/search.hh similarity index 100% rename from src/native/monodroid/jni/search.hh rename to src/native/monodroid/search.hh diff --git a/src/native/monodroid/jni/startup-aware-lock.hh b/src/native/monodroid/startup-aware-lock.hh similarity index 100% rename from src/native/monodroid/jni/startup-aware-lock.hh rename to src/native/monodroid/startup-aware-lock.hh diff --git a/src/native/monodroid/jni/timezones.cc b/src/native/monodroid/timezones.cc similarity index 100% rename from src/native/monodroid/jni/timezones.cc rename to src/native/monodroid/timezones.cc diff --git a/src/native/monodroid/jni/timing-internal.cc b/src/native/monodroid/timing-internal.cc similarity index 100% rename from src/native/monodroid/jni/timing-internal.cc rename to src/native/monodroid/timing-internal.cc diff --git a/src/native/monodroid/jni/timing-internal.hh b/src/native/monodroid/timing-internal.hh similarity index 100% rename from src/native/monodroid/jni/timing-internal.hh rename to src/native/monodroid/timing-internal.hh diff --git a/src/native/monodroid/jni/timing.cc b/src/native/monodroid/timing.cc similarity index 100% rename from src/native/monodroid/jni/timing.cc rename to src/native/monodroid/timing.cc diff --git a/src/native/monodroid/jni/timing.hh b/src/native/monodroid/timing.hh similarity index 100% rename from src/native/monodroid/jni/timing.hh rename to src/native/monodroid/timing.hh diff --git a/src/native/monodroid/jni/win32/jni_md.h b/src/native/monodroid/win32/jni_md.h similarity index 100% rename from src/native/monodroid/jni/win32/jni_md.h rename to src/native/monodroid/win32/jni_md.h diff --git a/src/native/monodroid/jni/xa-internal-api-impl.hh b/src/native/monodroid/xa-internal-api-impl.hh similarity index 100% rename from src/native/monodroid/jni/xa-internal-api-impl.hh rename to src/native/monodroid/xa-internal-api-impl.hh diff --git a/src/native/monodroid/jni/xa-internal-api.cc b/src/native/monodroid/xa-internal-api.cc similarity index 100% rename from src/native/monodroid/jni/xa-internal-api.cc rename to src/native/monodroid/xa-internal-api.cc diff --git a/src/native/monodroid/jni/xa-internal-api.hh b/src/native/monodroid/xa-internal-api.hh similarity index 100% rename from src/native/monodroid/jni/xa-internal-api.hh rename to src/native/monodroid/xa-internal-api.hh diff --git a/src/native/monodroid/jni/xamarin-android-app-context.cc b/src/native/monodroid/xamarin-android-app-context.cc similarity index 100% rename from src/native/monodroid/jni/xamarin-android-app-context.cc rename to src/native/monodroid/xamarin-android-app-context.cc diff --git a/src/native/monodroid/jni/xamarin_getifaddrs.cc b/src/native/monodroid/xamarin_getifaddrs.cc similarity index 100% rename from src/native/monodroid/jni/xamarin_getifaddrs.cc rename to src/native/monodroid/xamarin_getifaddrs.cc diff --git a/src/native/monodroid/jni/xamarin_getifaddrs.h b/src/native/monodroid/xamarin_getifaddrs.h similarity index 100% rename from src/native/monodroid/jni/xamarin_getifaddrs.h rename to src/native/monodroid/xamarin_getifaddrs.h diff --git a/src/native/native.targets b/src/native/native.targets index 67bb4bb46d9..77965fa9240 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -5,6 +5,22 @@ DependsOnTargets="_ConfigureRuntimes;_BuildAndroidRuntimes;_BuildAndroidAnalyzerRuntimes;_CopyToPackDirs"> + + + + + + + + + <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> @@ -94,7 +110,15 @@ - <_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" /> @@ -119,7 +143,7 @@ Date: Wed, 24 Apr 2024 16:22:39 +0200 Subject: [PATCH 22/49] Remove unneded include dirs --- src/native/monodroid/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index ed27b2429d6..a8d067baed5 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -138,10 +138,9 @@ target_compile_options( target_include_directories( ${XAMARIN_MONO_ANDROID_LIB} BEFORE PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/include/ ${CMAKE_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include ${EXTERNAL_DIR} ${ROBIN_MAP_DIR}/include - jni ) target_include_directories( From 4d5f1102195f85371aae480b368d2962e365b685 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 24 Apr 2024 14:59:56 +0200 Subject: [PATCH 23/49] Added perfetto submodule --- .gitmodules | 3 +++ external/perfetto | 1 + 2 files changed, 4 insertions(+) create mode 160000 external/perfetto diff --git a/.gitmodules b/.gitmodules index ac10c71f961..5b75f5c24db 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,3 +32,6 @@ path = external/libunwind url = https://github.com/libunwind/libunwind.git branch = master +[submodule "external/perfetto"] + path = external/perfetto + url = https://github.com/google/perfetto.git diff --git a/external/perfetto b/external/perfetto new file mode 160000 index 00000000000..eb5ef24c58d --- /dev/null +++ b/external/perfetto @@ -0,0 +1 @@ +Subproject commit eb5ef24c58d13cec289d733d03f0f3f0ed321b12 From e9ca94cb7df6f9a49c0a5558eea3055ba2e4e297 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 24 Apr 2024 16:23:43 +0200 Subject: [PATCH 24/49] Added perfetto --- src/native/CMakeLists.txt | 1 + src/native/monodroid/CMakeLists.txt | 163 +++++++++++++++++----------- src/native/perfetto/CMakeLists.txt | 40 +++++++ 3 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 src/native/perfetto/CMakeLists.txt diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 3ed2976b575..9cea66feba3 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -442,6 +442,7 @@ add_link_options("$<$:${COMMON_C_LINKER_ARGS}>") add_subdirectory(libunwind) add_subdirectory(lz4) +add_subdirectory(perfetto) add_subdirectory(libstub) add_subdirectory(shared) add_subdirectory(java-interop) diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index a8d067baed5..fdfdcc9dae9 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -42,8 +42,9 @@ 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_MONO_ANDROID_PERFETTO_LIB "mono-android-perfetto.${XAMARIN_MONO_ANDROID_SUFFIX}") -set(XAMARIN_MONODROID_SOURCES +list(APPEND XAMARIN_MONODROID_COMMON_SOURCES debug-constants.cc debug.cc embedded-assemblies-zip.cc @@ -64,12 +65,8 @@ set(XAMARIN_MONODROID_SOURCES xamarin_getifaddrs.cc ) -list(APPEND LOCAL_CLANG_CHECK_SOURCES - ${XAMARIN_MONODROID_SOURCES} -) - if(NOT DEBUG_BUILD) - list(APPEND XAMARIN_MONODROID_SOURCES + list(APPEND XAMARIN_MONODROID_COMMON_SOURCES xamarin-android-app-context.cc ) @@ -77,7 +74,14 @@ if(NOT DEBUG_BUILD) xamarin-android-app-context.cc ) endif() -add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") + +list(APPEND XAMARIN_MONODROID_SOURCES + ${XAMARIN_MONODROID_COMMON_SOURCES} +) + +list(APPEND XAMARIN_MONODROID_PERFETTO_SOURCES + ${XAMARIN_MONODROID_COMMON_SOURCES} +) if(NOT USES_LIBSTDCPP) list(APPEND XAMARIN_MONODROID_SOURCES @@ -85,6 +89,8 @@ if(NOT USES_LIBSTDCPP) ) endif() +add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") + # Build configure_file(host-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/host-config.h) @@ -93,78 +99,90 @@ add_library( 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(NOT ANALYZERS_ENABLED) + add_library( + ${XAMARIN_MONO_ANDROID_PERFETTO_LIB} + SHARED ${XAMARIN_MONODROID_PERFETTO_SOURCES} + ) +endif() -if(DONT_INLINE) +macro(set_common_monodroid_properties TARGET) target_compile_definitions( - ${XAMARIN_MONO_ANDROID_LIB} + ${TARGET} PRIVATE - NO_INLINE + HAVE_CONFIG_H + HAVE_LZ4 + JI_DLL_EXPORT + JI_NO_VISIBILITY + MONO_DLL_EXPORT + NET + TSL_NO_EXCEPTIONS ) -endif() -if(DEBUG_BUILD AND NOT DISABLE_DEBUG) - target_compile_definitions( - ${XAMARIN_MONO_ANDROID_LIB} + if(DONT_INLINE) + target_compile_definitions( + ${TARGET} + PRIVATE + NO_INLINE + ) + endif() + + if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + target_compile_definitions( + ${TARGET} + PRIVATE + DEBUG + ) + endif() + + target_compile_options( + ${TARGET} PRIVATE - DEBUG + ${XA_DEFAULT_SYMBOL_VISIBILITY} ) -endif() -if (ENABLE_TIMING) - target_compile_definitions( - ${XAMARIN_MONO_ANDROID_LIB} + target_include_directories( + ${TARGET} BEFORE PRIVATE - MONODROID_TIMING + ${CMAKE_CURRENT_BINARY_DIR}/include/ + ${NATIVE_TRACING_INCLUDE_DIRS} + ${EXTERNAL_DIR} + ${ROBIN_MAP_DIR}/include ) -endif() -target_compile_options( - ${XAMARIN_MONO_ANDROID_LIB} - PRIVATE - ${XA_DEFAULT_SYMBOL_VISIBILITY} -) + target_include_directories( + ${TARGET} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} + ${LIBUNWIND_INCLUDE_DIRS} + ) -target_include_directories( - ${XAMARIN_MONO_ANDROID_LIB} BEFORE - PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/include - ${EXTERNAL_DIR} - ${ROBIN_MAP_DIR}/include -) + target_link_directories( + ${TARGET} + PRIVATE + ${NET_RUNTIME_DIR}/native + ) -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_options( + ${TARGET} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} + ) +endmacro() -target_link_directories( - ${XAMARIN_MONO_ANDROID_LIB} - PRIVATE - ${NET_RUNTIME_DIR}/native -) +set_common_monodroid_properties(${XAMARIN_MONO_ANDROID_LIB}) +xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) -target_link_options( - ${XAMARIN_MONO_ANDROID_LIB} - PRIVATE - ${XA_DEFAULT_SYMBOL_VISIBILITY} - ${XA_COMMON_CXX_LINKER_ARGS} - ${XA_CXX_DSO_LINKER_ARGS} -) +if (ENABLE_TIMING) + target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + MONODROID_TIMING + ) +endif() target_link_libraries( ${XAMARIN_MONO_ANDROID_LIB} @@ -178,4 +196,19 @@ target_link_libraries( -llog ) -xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) +if(NOT ANALYZERS_ENABLED) + set_common_monodroid_properties(${XAMARIN_MONO_ANDROID_PERFETTO_LIB}) + xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_PERFETTO_LIB}) + + target_link_libraries( + ${XAMARIN_MONO_ANDROID_PERFETTO_LIB} + ${LINK_LIBS} + xa::xamarin-app + xa::shared-no-abi + xa::runtime-base + xa::java-interop + xa::lz4 + -lmonosgen-2.0 + -llog +) +endif() diff --git a/src/native/perfetto/CMakeLists.txt b/src/native/perfetto/CMakeLists.txt new file mode 100644 index 00000000000..3b5bcc570d5 --- /dev/null +++ b/src/native/perfetto/CMakeLists.txt @@ -0,0 +1,40 @@ +set(LIB_NAME xa-perfetto) +set(LIB_ALIAS xa::perfetto) + +set(PERFETTO_SRC_DIR "${EXTERNAL_DIR}/perfetto/sdk") +set(PERFETTO_INCLUDE_DIR ${PERFETTO_SRC_DIR}) + +set(PERFETTO_SOURCES + ${PERFETTO_SRC_DIR}/perfetto.cc +) + +add_library( + ${LIB_NAME} + STATIC + ${PERFETTO_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +find_package(Threads) + +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" + "$" +) + +target_link_libraries( + ${LIB_NAME} + PUBLIC + "$" +) + +set_target_properties( + ${LIB_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) + +xa_add_compile_definitions(${LIB_NAME}) From 988f9696d9642b53547e0624d569f1c8f2bfe8f7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 24 Apr 2024 17:09:14 +0200 Subject: [PATCH 25/49] Build and package monodroid runtime which includes the Perfetto SDK Perfetto APIs not used yet --- .../Microsoft.Android.Runtime.proj | 2 + src/native/CMakeLists.txt | 17 +++- src/native/CMakePresets.json.in | 70 +++++++++++++--- src/native/monodroid/CMakeLists.txt | 82 +++++++++---------- src/native/native.targets | 28 +++++++ 5 files changed, 142 insertions(+), 57 deletions(-) diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 6ccb3fa4847..a4838cf029c 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -40,6 +40,8 @@ projects that use the Microsoft.Android framework in .NET 6+. <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\Mono.Android.Export.dll" /> <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so" /> <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so" /> + <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android-perfetto.debug.so" /> + <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android-perfetto.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/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 9cea66feba3..990513d8c78 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -63,8 +63,13 @@ endif() option(ENABLE_CLANG_ASAN "Enable the clang AddressSanitizer support" OFF) option(ENABLE_CLANG_UBSAN "Enable the clang UndefinedBehaviorSanitizer support" OFF) +option(ENABLE_PERFETTO "Enable use of perfetto." OFF) if(ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) + if(ENABLE_PERFETT) + message(FATAL_ERROR "Perfetto and analyzer builds cannot be enabled at the same time") + endif() + set(STRIP_DEBUG_DEFAULT OFF) set(ANALYZERS_ENABLED ON) else() @@ -99,11 +104,11 @@ else() set(USES_LIBSTDCPP True) endif() -if(ANALYZERS_ENABLED) - message(STATUS "Analyzers enabled") +if(ANALYZERS_ENABLED OR ENABLE_PERFETTO) + message(STATUS "Analyzers or perfetto enabled") set(SHARED_LIB_NAME xa::shared-no-abi) else() - message(STATUS "NO analyzers enabled") + message(STATUS "NO analyzers or perfetto enabled") set(SHARED_LIB_NAME xa::shared) endif() # @@ -442,7 +447,11 @@ add_link_options("$<$:${COMMON_C_LINKER_ARGS}>") add_subdirectory(libunwind) add_subdirectory(lz4) -add_subdirectory(perfetto) + +if(ENABLE_PERFETTO) + add_subdirectory(perfetto) +endif() + add_subdirectory(libstub) add_subdirectory(shared) add_subdirectory(java-interop) diff --git a/src/native/CMakePresets.json.in b/src/native/CMakePresets.json.in index 51ae5802202..21982e8cb6c 100644 --- a/src/native/CMakePresets.json.in +++ b/src/native/CMakePresets.json.in @@ -53,7 +53,7 @@ }, { - "name": "analyzers-common", + "name": "use-stdlib", "hidden": true, "inherits": "common", "cacheVariables": { @@ -77,13 +77,13 @@ { "name": "analyzers-debug", "hidden": true, - "inherits": ["analyzers-common", "common-debug"] + "inherits": ["use-stdlib", "common-debug"] }, { "name": "analyzers-release", "hidden": true, - "inherits": ["analyzers-common", "common-release"] + "inherits": ["use-stdlib", "common-release"] }, { @@ -130,6 +130,14 @@ } }, + { + "name": "perfetto-common", + "hidden": true, + "cacheVariables": { + "ENABLE_PERFETTO": "ON" + } + }, + { "name": "asan-common", "hidden": true, @@ -156,16 +164,26 @@ "inherits": ["default-common", "common-release", "common-armeabi-v7a"] }, + { + "name": "perfetto-debug-armeabi-v7a", + "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-armeabi-v7a"] + }, + + { + "name": "perfetto-release-armeabi-v7a", + "inherits": ["use-stdlib", "perfetto-common", "common-release", "common-armeabi-v7a"] + }, + { "name": "analyzers-debug-armeabi-v7a", "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-armeabi-v7a"] + "inherits": ["use-stdlib", "common-debug", "common-armeabi-v7a"] }, { "name": "analyzers-release-armeabi-v7a", "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-armeabi-v7a"] + "inherits": ["use-stdlib", "common-release", "common-armeabi-v7a"] }, { @@ -200,16 +218,26 @@ "inherits": ["default-common", "common-release", "common-arm64-v8a"] }, + { + "name": "perfetto-debug-arm64-v8a", + "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-arm64-v8a"] + }, + + { + "name": "perfetto-release-arm64-v8a", + "inherits": ["use-stdlib", "perfetto-common", "common-release", "common-arm64-v8a"] + }, + { "name": "analyzers-debug-arm64-v8a", "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-arm64-v8a"] + "inherits": ["use-stdlib", "common-debug", "common-arm64-v8a"] }, { "name": "analyzers-release-arm64-v8a", "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-arm64-v8a"] + "inherits": ["use-stdlib", "common-release", "common-arm64-v8a"] }, { @@ -244,16 +272,26 @@ "inherits": ["default-common", "common-release", "common-x86"] }, + { + "name": "perfetto-debug-x86", + "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-x86"] + }, + + { + "name": "perfetto-release-x86", + "inherits": ["use-stdlib", "perfetto-common", "common-release", "common-x86"] + }, + { "name": "analyzers-debug-x86", "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-x86"] + "inherits": ["use-stdlib", "common-debug", "common-x86"] }, { "name": "analyzers-release-x86", "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-x86"] + "inherits": ["use-stdlib", "common-release", "common-x86"] }, { @@ -288,16 +326,26 @@ "inherits": ["default-common", "common-release", "common-x86_64"] }, + { + "name": "perfetto-debug-x86_64", + "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-x86_64"] + }, + + { + "name": "perfetto-release-x86_64", + "inherits": ["use-stdlib", "perfetto-common", "common-release", "common-x86_64"] + }, + { "name": "analyzers-debug-x86_64", "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-x86_64"] + "inherits": ["use-stdlib", "common-debug", "common-x86_64"] }, { "name": "analyzers-release-x86_64", "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-x86_64"] + "inherits": ["use-stdlib", "common-release", "common-x86_64"] }, { diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index fdfdcc9dae9..d4f44be90bf 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -94,18 +94,6 @@ add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") # 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} -) - -if(NOT ANALYZERS_ENABLED) - add_library( - ${XAMARIN_MONO_ANDROID_PERFETTO_LIB} - SHARED ${XAMARIN_MONODROID_PERFETTO_SOURCES} - ) -endif() - macro(set_common_monodroid_properties TARGET) target_compile_definitions( ${TARGET} @@ -173,42 +161,52 @@ macro(set_common_monodroid_properties TARGET) ) endmacro() -set_common_monodroid_properties(${XAMARIN_MONO_ANDROID_LIB}) -xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) - -if (ENABLE_TIMING) - target_compile_definitions( +if(NOT ENABLE_PERFETTO) + add_library( ${XAMARIN_MONO_ANDROID_LIB} - PRIVATE - MONODROID_TIMING + SHARED ${XAMARIN_MONODROID_SOURCES} ) -endif() -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 -) + set_common_monodroid_properties(${XAMARIN_MONO_ANDROID_LIB}) + xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) + + if (ENABLE_TIMING) + target_compile_definitions( + ${XAMARIN_MONO_ANDROID_LIB} + PRIVATE + MONODROID_TIMING + ) + endif() + + 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 + ) +else() + add_library( + ${XAMARIN_MONO_ANDROID_PERFETTO_LIB} + SHARED ${XAMARIN_MONODROID_PERFETTO_SOURCES} + ) -if(NOT ANALYZERS_ENABLED) set_common_monodroid_properties(${XAMARIN_MONO_ANDROID_PERFETTO_LIB}) xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_PERFETTO_LIB}) target_link_libraries( - ${XAMARIN_MONO_ANDROID_PERFETTO_LIB} - ${LINK_LIBS} - xa::xamarin-app - xa::shared-no-abi - xa::runtime-base - xa::java-interop - xa::lz4 - -lmonosgen-2.0 - -llog -) + ${XAMARIN_MONO_ANDROID_PERFETTO_LIB} + ${LINK_LIBS} + xa::xamarin-app + xa::shared-no-abi + xa::runtime-base + xa::java-interop + xa::lz4 + -lmonosgen-2.0 + -llog + ) endif() diff --git a/src/native/native.targets b/src/native/native.targets index 77965fa9240..fcf9499ff4b 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -38,12 +38,16 @@ <_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)-perfetto-Debug\CMakeCache.txt')" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-perfetto-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)-perfetto-Debug" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-perfetto-Release" /> <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> @@ -74,6 +78,18 @@ --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset perfetto-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-perfetto-Debug + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset perfetto-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-perfetto-Release + @@ -127,10 +143,14 @@ <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-perfetto-Debug\CMakeCache.txt')" /> + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-perfetto-Release\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(_MonoDroidSources)" /> <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.debug.so')" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.release.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-perfetto.debug.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android-perfetto.release.so')" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app.so')" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app.so')" /> @@ -154,6 +174,14 @@ Command="$(NinjaPath) -v" WorkingDirectory="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> + + + + From 297aacd1d7878ee2ead8c79884cf3fcb42679d2f Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 24 Apr 2024 20:09:02 -0500 Subject: [PATCH 26/49] [Mono.Android] fix potential leak of RunnableImplementors (#8900) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context: https://github.com/dotnet/maui/issues/18757 Context: https://github.com/dotnet/maui/pull/22007 Context: https://github.com/dotnet/maui/blob/440fa7f6ff5602e9cbe23249df5d13c45fb261e1/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewRenderer.cs#L484-L491 Context: https://github.com/xamarin/monodroid/commit/f4ffb99facfe4f77ed07230a9d4450ea5451e0c5 Context: 5777337e7874a8f2361998ef022db85ba9fc620a [`android.view.View.post(Runnable)`][0] adds a `Runnable` callback to the message queue, to be later run on the UI thread. Commit xamarin/monodroid@f4ffb99f, imported in 5777337e, added a `View.Post(Action)` overload for this method to make it easier to use. There is also a [`View.removeCallbacks(Runnable)`][1] method which allows removing the specified callback from the message queue. A `View.RemoveCallbacks(Action)` method was also added, permitting: Action a = () => …; View v = new View(context); v.Post(a); v.RemoveCallbacks(a); To make this work, we needed a way look up the `java.lang.Runnable` that corresponds to a given `Action`. Enter `RunnableImplementor` and `RunnableImplementor.instances`: namespace Java.Lang; partial class Thread { internal partial class RunnableImplementor : Java.Lang.Object, IRunnable { public RunnableImplementor (Action handler, bool removable = false); public void Run(); static Dictionary instances; public static RunnableImplementor Remove(Action handler); } } which can be used in the `View` overloads (simplified for exposition): namespace Android.Views; partial class View { public bool Post(Action action) => Post(new RunnableImplementor(action, removable: true)); public bool RemoveCallbacks(Action action) => RemoveCallbacks(RunnableImplementor.Remove(action)); } This works, but there's a problem [^0]: when `removable:true` is used, then `handler` is added to `instances`, and `handler` is only removed when: 1. `RunnableImplementor.Run()` is invoked, or 2. `RunnableImplementor.Remove(Action)` is invoked. `RunnableImplementor.Remove(Action)` is only invoked if `View.RemoveAction()` is invoked. Thus, the question: is there a way to use `View.Post()` and *not* invoke `RunnableImplementor.Run()`? Turns Out™, ***Yes***: var v = new View(context); v.Post(() => …); then…do nothing with `v`. While the `View.post(Runnable)` docs state: > Causes the Runnable to be added to the message queue. > The runnable will be run on the user interface thread. that's not *quite* true. More specifically, the `Runnable`s added to the `View` via `View.post(Runnable)` are only *actually* added to the message queue *if and when* the `View` is added to a `Window` [^1]. If the `View` is never added to a `Window`, then *all the `Runnable`s are never invoked*. Which brings us to the C# leak: if we call `View.Post(Action)` and never add the `View` to a `Window`, then `RunnableImplementor.Run()` is never executed. If `RunnableImplementor.Run()` isn't executed, then the `RunnableImplementor` instance will never be removed from `RunnableImplementor.instances`, and as `instances` is a "GC root" it will keep *all of* the `RunnableImplementor` instance, the Java-side `RunnableImplementor` peer instance (via GREF), and the `Action` alive, forever. I could observe this behavior in a MAUI unit test that: 1. Creates a `ListView` 2. Creates the platform view that implements `ListView` 3. Never adds any of these objects to the `Window` 4. Makes sure none of the things leak -- *this fails* Fix this by changing `RunnableImplementor.instances` to be a `ConditionalWeakTable`. This *prevents* `RunnableImplementor.instances` from acting as a GC root, allowing both the `Action` keys and `RunnableImplementor` values to be collected. dotnet/maui#18757 is more or less the same scenario, with one added Reproduction step that should be called out: > * Calling `View.Post(Action)` repeatedly (e.g. in a loop, on a > timer etc) will eventually cause the application to crash with > the message global reference table overflow *This particular part is not solvable*. Android has a GREF limit of ~52000 entries. If you try to create ~52000 GREFs in a way that doesn't allow the GC to collect things, then the app will crash, and there is nothing we can do about it: var v = new View(context); for (int i = 0; i < 53000; ++i) { int x = i; v.Post(() => Console.WriteLine(x)); } // Boom; attempting to add 53k Actions to a View will require // creating 53k `RunnableImplementor` instances, which will // create 53k GREFs, which will cause a Very Bad Time™. TODO: Address [^0] and dispose of the `RunnableImplementor` instance when `View.Post()` returns `false`. [0]: https://developer.android.com/reference/android/view/View#post(java.lang.Runnable) [1]: https://developer.android.com/reference/android/view/View#removeCallbacks(java.lang.Runnable) [2]: https://cs.android.com/android/platform/superproject/+/main:frameworks/base/core/java/android/view/View.java;l=19618 [3]: https://cs.android.com/android/platform/superproject/+/main:frameworks/base/core/java/android/view/View.java;l=21363 [^0]: There's at least two problems; another problem is that we leak if `View.post(Runnable)` returns *false*. This will be addressed later. [^1]: If you never add the `View` to a `Window`, then the `Runnables` just hang around until the GC decides to collect them: 1. When a `View` is *not* attached to a `Window`, then `View.mAttachInfo` is null, [so we call `getRunQueue()`][2]: public boolean post(Runnable action) { … getRunQueue().post(action); return true; } 2. `View.getRunQueue()` creates a `HandlerActionQueue`, sets `View.mRunQueue`. 3. The only place `View.mRunQueue` is "meaningfully used" is within [`View.dispatchAttachedToWindow()`][3], which "transfers" the `Runnables` within the `HandlerActionQueue` to the UI handler. 4. `View.dispatchAttachedToWindow()` is only executed when the `View` is attacked to a `Window`. --- src/Mono.Android/Java.Lang/Thread.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mono.Android/Java.Lang/Thread.cs b/src/Mono.Android/Java.Lang/Thread.cs index 8c6155f41d3..cc45dd16aed 100644 --- a/src/Mono.Android/Java.Lang/Thread.cs +++ b/src/Mono.Android/Java.Lang/Thread.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Android.Runtime; @@ -27,7 +28,7 @@ public RunnableImplementor (Action handler, bool removable) this.removable = removable; if (removable) lock (instances) - instances [handler] = this; + instances.AddOrUpdate (handler, this); } public void Run () @@ -41,7 +42,7 @@ public void Run () Dispose (); } - static Dictionary instances = new Dictionary (); + static ConditionalWeakTable instances = new (); public static RunnableImplementor Remove (Action handler) { From 7d0165e49b7df7f8bb2445fbc9b8ed7fe1a37c37 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 25 Apr 2024 21:08:58 +0200 Subject: [PATCH 27/49] Figuring out how to trace events --- src/native/CMakeLists.txt | 17 +++ src/native/monodroid/CMakeLists.txt | 1 + .../monodroid/monodroid-glue-internal.hh | 28 ++++ src/native/monodroid/monodroid-glue.cc | 123 ++++++++++++++++++ src/native/shared/cppcompat.hh | 4 + 5 files changed, 173 insertions(+) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 990513d8c78..f68d438ff8b 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -171,6 +171,23 @@ macro(xa_add_compile_definitions TARGET) PLATFORM_ANDROID ) + if(ENABLE_PERFETTO) + target_compile_definitions( + ${TARGET} + PRIVATE + PERFETTO_ENABLED + USES_LIBSTDCPP + ) + endif() + + if(ENABLE_PERFETTO OR ANALYZERS_ENABLED) + target_compile_definitions( + ${TARGET} + PRIVATE + USES_LIBSTDCPP + ) + endif() + if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") target_compile_definitions( ${TARGET} diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index d4f44be90bf..3f5b089311e 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -206,6 +206,7 @@ else() xa::runtime-base xa::java-interop xa::lz4 + xa::perfetto -lmonosgen-2.0 -llog ) diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index a8245495dd4..7105e64ca01 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -12,6 +12,7 @@ #include "cpp-util.hh" #include "xxhash.hh" +#include #include #include @@ -205,6 +206,9 @@ namespace xamarin::android::internal void log_traces (JNIEnv *env, TraceKind kind, const char *first_line) noexcept; private: +#if defined(PERFETTO_ENABLED) + static void init_perfetto () noexcept; +#endif static void mono_log_handler (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); static void mono_log_standard_streams_handler (const char *str, mono_bool is_stdout); @@ -290,6 +294,30 @@ namespace xamarin::android::internal static void jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo); static void thread_start (MonoProfiler *prof, uintptr_t tid); static void thread_end (MonoProfiler *prof, uintptr_t tid); + static void prof_assembly_loading (MonoProfiler *prof, MonoAssembly *assembly) noexcept; + static void prof_assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) noexcept; + static void prof_image_loading (MonoProfiler *prof, MonoImage *assembly) noexcept; + static void prof_image_loaded (MonoProfiler *prof, MonoImage *assembly) noexcept; + static void prof_class_loading (MonoProfiler *prof, MonoClass *klass) noexcept; + static void prof_class_loaded (MonoProfiler *prof, MonoClass *klass) noexcept; + static void prof_vtable_loading (MonoProfiler *prof, MonoVTable *vtable) noexcept; + static void prof_vtable_loaded (MonoProfiler *prof, MonoVTable *vtable) noexcept; + static void prof_method_enter (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context) noexcept; + static void prof_method_leave (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context) noexcept; + static void prof_method_begin_invoke (MonoProfiler *prof, MonoMethod *method) noexcept; + static void prof_method_end_invoke (MonoProfiler *prof, MonoMethod *method) noexcept; + static void prof_monitor_contention (MonoProfiler *prof, MonoObject *object) noexcept; + static void prof_monitor_acquired (MonoProfiler *prof, MonoObject *object) noexcept; + + template + static void get_full_class_name (MonoClass *klass, internal::dynamic_local_string& info) noexcept + { + info.append (mono_class_get_namespace (klass)); + if (info.length () > 0) { + info.append ("."); + } + info.append (mono_class_get_name (klass)); + } #if !defined (RELEASE) static MonoReflectionType* typemap_java_to_managed (MonoString *java_type_name) noexcept; static const char* typemap_managed_to_java (MonoReflectionType *type, const uint8_t *mvid) noexcept; diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index bde0d634242..0c0c6144ea5 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -40,6 +40,10 @@ #include "mono_android_Runtime.h" +#if defined (PERFETTO_ENABLED) +#include +#endif + #if defined (DEBUG) #include #include @@ -77,6 +81,14 @@ using namespace microsoft::java_interop; using namespace xamarin::android; using namespace xamarin::android::internal; +#if defined(PERFETTO_ENABLED) +PERFETTO_DEFINE_CATEGORIES( + perfetto::Category ("managed-runtime").SetDescription ("Events from the MonoVM runtime"), +); + +PERFETTO_TRACK_EVENT_STATIC_STORAGE(); +#endif + std::mutex MonodroidRuntime::pinvoke_map_write_lock; MonoCoreRuntimeProperties MonodroidRuntime::monovm_core_properties = { @@ -532,6 +544,103 @@ MonodroidRuntime::set_debug_options (void) mono_debug_init (MONO_DEBUG_FORMAT_MONO); } +void +MonodroidRuntime::prof_assembly_loading ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto id = reinterpret_cast(assembly); + auto track = perfetto::Track (id); + auto desc = track.Serialize (); + desc.set_name ("assembly_name"); + perfetto::TrackEvent::SetTrackDescriptor (track, desc); + TRACE_EVENT_BEGIN ("managed-runtime", "Assembly load", track); +#endif +} + +void +MonodroidRuntime::prof_assembly_loaded ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto id = reinterpret_cast(assembly); + auto track = perfetto::Track (id); + auto desc = track.Serialize (); + desc.set_name ("assembly_name"); + TRACE_EVENT_END ("managed-runtime", track); +#endif +} + +void +MonodroidRuntime::prof_image_loading ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept +{ + +} + +void +MonodroidRuntime::prof_image_loaded ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept +{ + +} + +void +MonodroidRuntime::prof_class_loading ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept +{ + +} + +void +MonodroidRuntime::prof_class_loaded ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept +{ + +} + +void +MonodroidRuntime::prof_vtable_loading ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept +{ + +} + +void +MonodroidRuntime::prof_vtable_loaded ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept +{ + +} + +void +MonodroidRuntime::prof_method_begin_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept +{ + +} + +void +MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept +{ + +} + +void +MonodroidRuntime::prof_method_enter ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept +{ + +} + +void +MonodroidRuntime::prof_method_leave ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept +{ + +} + +void +MonodroidRuntime::prof_monitor_contention ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept +{ + +} + +void +MonodroidRuntime::prof_monitor_acquired ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept +{ + +} + void MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] dynamic_local_string& runtime_args) { @@ -1560,12 +1669,26 @@ MonodroidRuntime::install_logging_handlers () mono_trace_set_printerr_handler (mono_log_standard_streams_handler); } +#if defined(PERFETTO_ENABLED) +void MonodroidRuntime::init_perfetto () noexcept +{ + perfetto::TracingInitArgs args; + args.backends = perfetto::kSystemBackend; + + perfetto::Tracing::Initialize (args); + perfetto::TrackEvent::Register (); +} +#endif + inline void MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, jobjectArray assembliesJava, jint apiLevel, jboolean isEmulator, jboolean haveSplitApks) { +#if defined(PERFETTO_ENABLED) + +#endif char *mono_log_mask_raw = nullptr; char *mono_log_level_raw = nullptr; diff --git a/src/native/shared/cppcompat.hh b/src/native/shared/cppcompat.hh index a802a2a12c3..f055140b22d 100644 --- a/src/native/shared/cppcompat.hh +++ b/src/native/shared/cppcompat.hh @@ -2,6 +2,9 @@ #ifndef __CPP_COMPAT_H #define __CPP_COMPAT_H +#if defined(USES_LIBSTDCPP) +#include +#else // def USES_LIBSTDCPP #include // We can't use on Android because it requires linking libc++ into the rutime, see below. @@ -63,5 +66,6 @@ namespace std pthread_mutex_t _pmutex = PTHREAD_MUTEX_INITIALIZER; }; } +#endif // ndef USES_LIBSTDCPP #endif From 7a6697c20db0d6061b00070b9aae3ac97f2ec6d8 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 26 Apr 2024 18:25:14 +0200 Subject: [PATCH 28/49] More research + some managed runtime events implemented --- src/native/monodroid/CMakeLists.txt | 1 - .../monodroid/monodroid-glue-internal.hh | 9 -- src/native/monodroid/monodroid-glue.cc | 78 ++++++++----- src/native/runtime-base/util.hh | 1 + src/native/shared/CMakeLists.txt | 15 +++ src/native/shared/perfetto_support.cc | 10 ++ src/native/shared/perfetto_support.hh | 108 ++++++++++++++++++ 7 files changed, 181 insertions(+), 41 deletions(-) create mode 100644 src/native/shared/perfetto_support.cc create mode 100644 src/native/shared/perfetto_support.hh diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 3f5b089311e..d4f44be90bf 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -206,7 +206,6 @@ else() xa::runtime-base xa::java-interop xa::lz4 - xa::perfetto -lmonosgen-2.0 -llog ) diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index 7105e64ca01..340bd00306b 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -309,15 +309,6 @@ namespace xamarin::android::internal static void prof_monitor_contention (MonoProfiler *prof, MonoObject *object) noexcept; static void prof_monitor_acquired (MonoProfiler *prof, MonoObject *object) noexcept; - template - static void get_full_class_name (MonoClass *klass, internal::dynamic_local_string& info) noexcept - { - info.append (mono_class_get_namespace (klass)); - if (info.length () > 0) { - info.append ("."); - } - info.append (mono_class_get_name (klass)); - } #if !defined (RELEASE) static MonoReflectionType* typemap_java_to_managed (MonoString *java_type_name) noexcept; static const char* typemap_managed_to_java (MonoReflectionType *type, const uint8_t *mvid) noexcept; diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index 0c0c6144ea5..4107240b10e 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #if defined (PERFETTO_ENABLED) #include +#include "perfetto_support.hh" #endif #if defined (DEBUG) @@ -81,14 +83,6 @@ using namespace microsoft::java_interop; using namespace xamarin::android; using namespace xamarin::android::internal; -#if defined(PERFETTO_ENABLED) -PERFETTO_DEFINE_CATEGORIES( - perfetto::Category ("managed-runtime").SetDescription ("Events from the MonoVM runtime"), -); - -PERFETTO_TRACK_EVENT_STATIC_STORAGE(); -#endif - std::mutex MonodroidRuntime::pinvoke_map_write_lock; MonoCoreRuntimeProperties MonodroidRuntime::monovm_core_properties = { @@ -548,12 +542,8 @@ void MonodroidRuntime::prof_assembly_loading ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept { #if defined(PERFETTO_ENABLED) - auto id = reinterpret_cast(assembly); - auto track = perfetto::Track (id); - auto desc = track.Serialize (); - desc.set_name ("assembly_name"); - perfetto::TrackEvent::SetTrackDescriptor (track, desc); - TRACE_EVENT_BEGIN ("managed-runtime", "Assembly load", track); + auto track = PerfettoSupport::get_name_annotated_track (assembly); + TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::AssemblyLoadAnnotation.data (), track); #endif } @@ -561,84 +551,110 @@ void MonodroidRuntime::prof_assembly_loaded ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept { #if defined(PERFETTO_ENABLED) - auto id = reinterpret_cast(assembly); - auto track = perfetto::Track (id); - auto desc = track.Serialize (); - desc.set_name ("assembly_name"); - TRACE_EVENT_END ("managed-runtime", track); + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (assembly)); #endif } void MonodroidRuntime::prof_image_loading ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept { - +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_track (image); + TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::ImageLoadAnnotation.data (), track); +#endif } void MonodroidRuntime::prof_image_loaded ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept { - +#if defined(PERFETTO_ENABLED) + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (image)); +#endif } void MonodroidRuntime::prof_class_loading ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept { - +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_track (klass); + TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::ClassLoadAnnotation.data (), track); +#endif } void MonodroidRuntime::prof_class_loaded ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept { - +#if defined(PERFETTO_ENABLED) + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (klass)); +#endif } void MonodroidRuntime::prof_vtable_loading ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept { - +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_track (vtable); + TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::VTableLoadAnnotation.data (), track); +#endif } void MonodroidRuntime::prof_vtable_loaded ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept { - +#if defined(PERFETTO_ENABLED) + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (vtable)); +#endif } void MonodroidRuntime::prof_method_begin_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept { - +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_track (method); + TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::MethodInvokeAnnotation.data (), track); +#endif } void MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept { - +#if defined(PERFETTO_ENABLED) + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (method)); +#endif } void MonodroidRuntime::prof_method_enter ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept { - +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_track (method); + TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::MethodRunTimeAnnotation.data (), track); +#endif } void MonodroidRuntime::prof_method_leave ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept { - +#if defined(PERFETTO_ENABLED) + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (method)); +#endif } void MonodroidRuntime::prof_monitor_contention ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept { - +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_track (object); + TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::MonitorContentionAnnotation.data (), track); +#endif } void MonodroidRuntime::prof_monitor_acquired ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept { - +#if defined(PERFETTO_ENABLED) + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (object)); +#endif } void diff --git a/src/native/runtime-base/util.hh b/src/native/runtime-base/util.hh index 718e2e87551..32f5f7f0a8a 100644 --- a/src/native/runtime-base/util.hh +++ b/src/native/runtime-base/util.hh @@ -33,6 +33,7 @@ static inline constexpr int FALSE = 0; #include #include +#include #include #include #include diff --git a/src/native/shared/CMakeLists.txt b/src/native/shared/CMakeLists.txt index 6deaaaf9d79..699b1114380 100644 --- a/src/native/shared/CMakeLists.txt +++ b/src/native/shared/CMakeLists.txt @@ -14,6 +14,13 @@ set(XA_SHARED_SOURCES log_functions.cc new_delete.cc ) + +if(ENABLE_PERFETTO) + list(APPEND XA_SHARED_SOURCES + perfetto_support.cc + ) +endif() + add_clang_check_sources("${XA_SHARED_SOURCES};${XA_SHARED_CXX_ABI_SOURCES}") set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") @@ -44,6 +51,14 @@ macro(lib_target_options TARGET_NAME) "$" ) + if(ENABLE_PERFETTO) + target_link_libraries( + ${TARGET_NAME} + PUBLIC + xa::perfetto + ) + endif() + target_link_libraries( ${TARGET_NAME} PUBLIC diff --git a/src/native/shared/perfetto_support.cc b/src/native/shared/perfetto_support.cc new file mode 100644 index 00000000000..0237c28aeda --- /dev/null +++ b/src/native/shared/perfetto_support.cc @@ -0,0 +1,10 @@ +#include "perfetto_support.hh" + +using namespace xamarin::android; + +PERFETTO_TRACK_EVENT_STATIC_STORAGE(); + +void PerfettoSupport::set_track_event_descriptor (perfetto::Track &track, perfetto::protos::gen::TrackDescriptor &desc) +{ + perfetto::TrackEvent::SetTrackDescriptor (track, desc); +} diff --git a/src/native/shared/perfetto_support.hh b/src/native/shared/perfetto_support.hh new file mode 100644 index 00000000000..edab86cf61f --- /dev/null +++ b/src/native/shared/perfetto_support.hh @@ -0,0 +1,108 @@ +#if !defined(PERFETTO_SUPPORT_HH) +#define PERFETTO_SUPPORT_HH + +#if defined(PERFETTO_ENABLED) +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cpp-util.hh" + +namespace xamarin::android { + class PerfettoConstants + { + public: + static constexpr std::string_view ManagedRuntimeCategory { "managed-runtime" }; + + static constexpr std::string_view AssemblyLoadAnnotation { "Assembly load" }; + static constexpr std::string_view ImageLoadAnnotation { "Assembly image load" }; + static constexpr std::string_view ClassLoadAnnotation { "Class load" }; + static constexpr std::string_view VTableLoadAnnotation { "VTable load" }; + static constexpr std::string_view MethodInvokeAnnotation { "Method invoke" }; + static constexpr std::string_view MethodRunTimeAnnotation { "Method inner run time" }; + static constexpr std::string_view MonitorContentionAnnotation { "Monitor contention" }; + }; +} + +PERFETTO_DEFINE_CATEGORIES ( + perfetto::Category (xamarin::android::PerfettoConstants::ManagedRuntimeCategory.data ()).SetDescription ("Events from the MonoVM runtime") +); + +namespace xamarin::android { + namespace detail { + template + concept SupportedMonoType = requires { + requires std::same_as || + std::same_as || + std::same_as || + std::same_as || + std::same_as || + std::same_as; + }; + } + + class PerfettoSupport + { + public: + template + force_inline static uint64_t get_track_id (TMonoType *data) + { + return reinterpret_cast(data); + } + + template + force_inline static perfetto::Track get_name_annotated_track (TMonoType *data) + { + auto track = perfetto::Track (get_track_id (data)); + auto desc = track.Serialize (); + + if constexpr (std::is_same_v) { + desc.set_name (mono_assembly_name_get_name (mono_assembly_get_name (data))); + } else if constexpr (std::is_same_v) { + desc.set_name (mono_image_get_name (data)); + } else if constexpr (std::is_same_v) { + std::string name{}; + append_full_class_name (data, name); + desc.set_name (name); + } else if constexpr (std::is_same_v) { + return get_name_annotated_track (mono_vtable_class (data)); + } else if constexpr (std::is_same_v) { + std::string name{}; + append_full_class_name (mono_method_get_class (data), name); + name.append ("."); + name.append (mono_method_get_name (data)); + desc.set_name (name); + } else if constexpr (std::is_same_v) { + return get_name_annotated_track (mono_object_get_class (data)); + } + set_track_event_descriptor (track, desc); + + return track; + } + + private: + static void append_full_class_name (const MonoClass *klass, std::string &name) + { + name.append (mono_class_get_namespace (const_cast(klass))); + name.append ("."); + name.append (mono_class_get_name (const_cast(klass))); + } + + private: + static void set_track_event_descriptor (perfetto::Track &track, perfetto::protos::gen::TrackDescriptor &desc); + }; +} +#endif // def PERFETTO_ENABLED + +#endif // ndef PERFETTO_SUPPORT_HH From 0ec8677e6079cbe7af81f48c99c58132e2746cfd Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 30 Apr 2024 15:04:00 +0200 Subject: [PATCH 29/49] Package only one runtime, either with or without Perfetto support --- .../targets/Microsoft.Android.Sdk.AssemblyResolution.targets | 5 +++++ 1 file changed, 5 insertions(+) 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 4ad281d2f17..aea519cb514 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 @@ -215,6 +215,7 @@ _ResolveAssemblies MSBuild target. <_AndroidIncludeSystemGlobalizationNative Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' == '' ">true <_AndroidEnableNativeStackTracing Condition=" '$(_AndroidEnableNativeStackTracing)' == ''">false + <_AndroidEnablePerfetto Condition=" '$(_AndroidEnablePerfetto)' == ''">false <_ResolvedNativeLibraries Include="@(ResolvedFileToPublish)" Condition=" '%(ResolvedFileToPublish.Extension)' == '.so' " /> @@ -227,6 +228,10 @@ _ResolveAssemblies MSBuild target. <_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidEnablePerfetto)' != 'true' " Include="libmono-android-perfetto.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidEnablePerfetto)' != 'true' " Include="libmono-android-perfetto.release" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidEnablePerfetto)' == 'true' " Include="libmono-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidEnablePerfetto)' == 'true' " Include="libmono-android.release" /> Date: Tue, 30 Apr 2024 16:18:26 +0200 Subject: [PATCH 30/49] Better, I hope --- .../Tasks/ProcessNativeLibraries.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs index 4970875d659..8765d305fd8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs @@ -63,7 +63,10 @@ public override bool RunTask () // Use IncludeDebugSymbols to determine which one to include. // We may eventually have files such as `libmono-android-checked+asan.release.so` as well. var fileName = Path.GetFileNameWithoutExtension (library.ItemSpec); - if (fileName.StartsWith ("libmono-android", StringComparison.Ordinal)) { + if (ExcludedLibraries != null && ExcludedLibraries.Contains (fileName, StringComparer.OrdinalIgnoreCase)) { + Log.LogDebugMessage ($"Excluding '{library.ItemSpec}'"); + continue; + } else if (fileName.StartsWith ("libmono-android", StringComparison.Ordinal)) { if (fileName.EndsWith (".debug", StringComparison.Ordinal)) { if (!IncludeDebugSymbols) continue; @@ -82,9 +85,6 @@ public override bool RunTask () if (!wantedComponents.Contains (fileName)) { continue; } - } else if (ExcludedLibraries != null && ExcludedLibraries.Contains (fileName, StringComparer.OrdinalIgnoreCase)) { - Log.LogDebugMessage ($"Excluding '{library.ItemSpec}'"); - continue; } output.Add (library); From a6988598a3b35bb85e825efca2632c1243331b35 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 7 May 2024 23:49:13 +0200 Subject: [PATCH 31/49] Experimenting with events --- .../monodroid/monodroid-glue-internal.hh | 1 + src/native/monodroid/monodroid-glue.cc | 43 ++++++++++++++++--- src/native/shared/perfetto_support.hh | 16 +++++-- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index 340bd00306b..ec67a49ad0c 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -208,6 +208,7 @@ namespace xamarin::android::internal private: #if defined(PERFETTO_ENABLED) static void init_perfetto () noexcept; + void perfetto_hook_mono_events () noexcept; #endif static void mono_log_handler (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); static void mono_log_standard_streams_handler (const char *str, mono_bool is_stdout); diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index 4107240b10e..2bcfa02026e 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -585,7 +585,8 @@ void MonodroidRuntime::prof_class_loaded ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept { #if defined(PERFETTO_ENABLED) - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (klass)); + auto track = PerfettoSupport::get_name_annotated_track (klass); + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), track); #endif } @@ -619,7 +620,8 @@ void MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept { #if defined(PERFETTO_ENABLED) - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (method)); + auto track = PerfettoSupport::get_name_annotated_track (method); + TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), track); #endif } @@ -777,7 +779,9 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse profiler_handle = mono_profiler_create (nullptr); mono_profiler_set_thread_started_callback (profiler_handle, thread_start); mono_profiler_set_thread_stopped_callback (profiler_handle, thread_end); - +#if defined (PERFETTO_ENABLED) + perfetto_hook_mono_events (); +#endif if (log_methods) [[unlikely]]{ jit_time.mark_start (); mono_profiler_set_jit_begin_callback (profiler_handle, jit_begin); @@ -1686,14 +1690,43 @@ MonodroidRuntime::install_logging_handlers () } #if defined(PERFETTO_ENABLED) -void MonodroidRuntime::init_perfetto () noexcept +void +MonodroidRuntime::init_perfetto () noexcept { + log_warn (LOG_TIMING, "INIT perfetto"); perfetto::TracingInitArgs args; args.backends = perfetto::kSystemBackend; perfetto::Tracing::Initialize (args); perfetto::TrackEvent::Register (); } + +void +MonodroidRuntime::perfetto_hook_mono_events () noexcept +{ + if (profiler_handle == nullptr) { + return; + } + + log_warn (LOG_TIMING, "HOOK perfetto"); + mono_profiler_set_assembly_loading_callback (profiler_handle, prof_assembly_loading); + mono_profiler_set_assembly_loaded_callback (profiler_handle, prof_assembly_loaded); + mono_profiler_set_image_loading_callback (profiler_handle, prof_image_loading); + mono_profiler_set_image_loaded_callback (profiler_handle, prof_image_loaded); + + mono_profiler_set_class_loading_callback (profiler_handle, prof_class_loading); + mono_profiler_set_class_loaded_callback (profiler_handle, prof_class_loaded); + mono_profiler_set_vtable_loading_callback (profiler_handle, prof_vtable_loading); + mono_profiler_set_vtable_loaded_callback (profiler_handle, prof_vtable_loaded); + mono_profiler_set_monitor_contention_callback (profiler_handle, prof_monitor_contention); + mono_profiler_set_monitor_acquired_callback (profiler_handle, prof_monitor_acquired); + + mono_profiler_set_method_begin_invoke_callback (profiler_handle, prof_method_begin_invoke); + mono_profiler_set_method_end_invoke_callback (profiler_handle, prof_method_end_invoke); + mono_profiler_set_method_enter_callback (profiler_handle, prof_method_enter); + mono_profiler_set_method_leave_callback (profiler_handle, prof_method_leave); + +} #endif inline void @@ -1703,7 +1736,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl jboolean haveSplitApks) { #if defined(PERFETTO_ENABLED) - + init_perfetto (); #endif char *mono_log_mask_raw = nullptr; char *mono_log_level_raw = nullptr; diff --git a/src/native/shared/perfetto_support.hh b/src/native/shared/perfetto_support.hh index edab86cf61f..45fd20da8f1 100644 --- a/src/native/shared/perfetto_support.hh +++ b/src/native/shared/perfetto_support.hh @@ -54,6 +54,14 @@ namespace xamarin::android { class PerfettoSupport { + force_inline static void set_desc_name (perfetto::protos::gen::TrackDescriptor &desc, const char *name) noexcept + { + if (name == nullptr) { + return; + } + desc.set_name (name); + } + public: template force_inline static uint64_t get_track_id (TMonoType *data) @@ -64,13 +72,14 @@ namespace xamarin::android { template force_inline static perfetto::Track get_name_annotated_track (TMonoType *data) { - auto track = perfetto::Track (get_track_id (data)); + auto track = perfetto::Track::FromPointer (data, perfetto::ThreadTrack::Current ()); auto desc = track.Serialize (); if constexpr (std::is_same_v) { - desc.set_name (mono_assembly_name_get_name (mono_assembly_get_name (data))); + MonoAssemblyName *asm_name = mono_assembly_get_name (data); + set_desc_name (desc, asm_name == nullptr ? nullptr : mono_assembly_name_get_name (asm_name)); } else if constexpr (std::is_same_v) { - desc.set_name (mono_image_get_name (data)); + set_desc_name (desc, mono_image_get_name (data)); } else if constexpr (std::is_same_v) { std::string name{}; append_full_class_name (data, name); @@ -87,7 +96,6 @@ namespace xamarin::android { return get_name_annotated_track (mono_object_get_class (data)); } set_track_event_descriptor (track, desc); - return track; } From cf4a8f60a72054bf45c3ea55cc6288b447d00191 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 8 May 2024 21:23:55 +0200 Subject: [PATCH 32/49] Now we're talkin' Events are recorded under the correct package name, organized in a track per event class. Some names are added as debug annotations (assembly and image name) since they're not available when the event starts and the event name must be the same at the beginning and at finish. --- .../monodroid/monodroid-glue-internal.hh | 2 +- src/native/monodroid/monodroid-glue.cc | 69 ++++++----- src/native/perfetto/CMakeLists.txt | 7 +- src/native/shared/perfetto_support.hh | 113 ++++++++++++------ 4 files changed, 124 insertions(+), 67 deletions(-) diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index ec67a49ad0c..8a4d747da94 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -207,7 +207,7 @@ namespace xamarin::android::internal private: #if defined(PERFETTO_ENABLED) - static void init_perfetto () noexcept; + static void perfetto_init () noexcept; void perfetto_hook_mono_events () noexcept; #endif static void mono_log_handler (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index 2bcfa02026e..7a73d1d57a1 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -542,8 +542,8 @@ void MonodroidRuntime::prof_assembly_loading ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (assembly); - TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::AssemblyLoadAnnotation.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::AssemblyLoadAnnotation.data (), track); #endif } @@ -551,7 +551,10 @@ void MonodroidRuntime::prof_assembly_loaded ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept { #if defined(PERFETTO_ENABLED) - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (assembly)); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, assembly); + }); #endif } @@ -559,8 +562,8 @@ void MonodroidRuntime::prof_image_loading ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (image); - TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::ImageLoadAnnotation.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::ImageLoadAnnotation.data (), track); #endif } @@ -568,7 +571,10 @@ void MonodroidRuntime::prof_image_loaded ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept { #if defined(PERFETTO_ENABLED) - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (image)); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, image); + }); #endif } @@ -576,8 +582,8 @@ void MonodroidRuntime::prof_class_loading ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (klass); - TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::ClassLoadAnnotation.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::ClassLoadAnnotation.data (), track); #endif } @@ -585,8 +591,8 @@ void MonodroidRuntime::prof_class_loaded ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (klass); - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track); #endif } @@ -594,8 +600,8 @@ void MonodroidRuntime::prof_vtable_loading ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (vtable); - TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::VTableLoadAnnotation.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::VTableLoadAnnotation.data (), track); #endif } @@ -603,7 +609,8 @@ void MonodroidRuntime::prof_vtable_loaded ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept { #if defined(PERFETTO_ENABLED) - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (vtable)); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track); #endif } @@ -611,8 +618,8 @@ void MonodroidRuntime::prof_method_begin_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (method); - TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::MethodInvokeAnnotation.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MethodInvokeAnnotation.data (), track); #endif } @@ -620,8 +627,10 @@ void MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (method); - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, method); + }); #endif } @@ -629,8 +638,8 @@ void MonodroidRuntime::prof_method_enter ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (method); - TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::MethodRunTimeAnnotation.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MethodRunTimeAnnotation.data (), track); #endif } @@ -638,7 +647,10 @@ void MonodroidRuntime::prof_method_leave ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept { #if defined(PERFETTO_ENABLED) - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (method)); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, method); + }); #endif } @@ -646,8 +658,8 @@ void MonodroidRuntime::prof_monitor_contention ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (object); - TRACE_EVENT_BEGIN (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoConstants::MonitorContentionAnnotation.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MonitorContentionAnnotation.data (), track); #endif } @@ -655,7 +667,8 @@ void MonodroidRuntime::prof_monitor_acquired ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept { #if defined(PERFETTO_ENABLED) - TRACE_EVENT_END (PerfettoConstants::ManagedRuntimeCategory.data (), PerfettoSupport::get_track_id (object)); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track); #endif } @@ -1691,7 +1704,7 @@ MonodroidRuntime::install_logging_handlers () #if defined(PERFETTO_ENABLED) void -MonodroidRuntime::init_perfetto () noexcept +MonodroidRuntime::perfetto_init () noexcept { log_warn (LOG_TIMING, "INIT perfetto"); perfetto::TracingInitArgs args; @@ -1716,8 +1729,8 @@ MonodroidRuntime::perfetto_hook_mono_events () noexcept mono_profiler_set_class_loading_callback (profiler_handle, prof_class_loading); mono_profiler_set_class_loaded_callback (profiler_handle, prof_class_loaded); - mono_profiler_set_vtable_loading_callback (profiler_handle, prof_vtable_loading); - mono_profiler_set_vtable_loaded_callback (profiler_handle, prof_vtable_loaded); + // mono_profiler_set_vtable_loading_callback (profiler_handle, prof_vtable_loading); + // mono_profiler_set_vtable_loaded_callback (profiler_handle, prof_vtable_loaded); mono_profiler_set_monitor_contention_callback (profiler_handle, prof_monitor_contention); mono_profiler_set_monitor_acquired_callback (profiler_handle, prof_monitor_acquired); @@ -1736,7 +1749,9 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl jboolean haveSplitApks) { #if defined(PERFETTO_ENABLED) - init_perfetto (); + perfetto_init (); + + TRACE_EVENT (PerfettoConstants::MonodroidCategory.data (), PerfettoConstants::XAInitInternal.data ()); #endif char *mono_log_mask_raw = nullptr; char *mono_log_level_raw = nullptr; diff --git a/src/native/perfetto/CMakeLists.txt b/src/native/perfetto/CMakeLists.txt index 3b5bcc570d5..1be1e464fd1 100644 --- a/src/native/perfetto/CMakeLists.txt +++ b/src/native/perfetto/CMakeLists.txt @@ -1,11 +1,12 @@ set(LIB_NAME xa-perfetto) set(LIB_ALIAS xa::perfetto) -set(PERFETTO_SRC_DIR "${EXTERNAL_DIR}/perfetto/sdk") -set(PERFETTO_INCLUDE_DIR ${PERFETTO_SRC_DIR}) +set(PERFETTO_DIR "${EXTERNAL_DIR}/perfetto") +set(PERFETTO_SDK_DIR "${PERFETTO_DIR}/sdk") +set(PERFETTO_INCLUDE_DIR "${PERFETTO_DIR}/sdk") set(PERFETTO_SOURCES - ${PERFETTO_SRC_DIR}/perfetto.cc + ${PERFETTO_SDK_DIR}/perfetto.cc ) add_library( diff --git a/src/native/shared/perfetto_support.hh b/src/native/shared/perfetto_support.hh index 45fd20da8f1..5fee1a59d01 100644 --- a/src/native/shared/perfetto_support.hh +++ b/src/native/shared/perfetto_support.hh @@ -23,20 +23,36 @@ namespace xamarin::android { class PerfettoConstants { public: - static constexpr std::string_view ManagedRuntimeCategory { "managed-runtime" }; + static constexpr std::string_view MonoRuntimeCategory { "mono-runtime" }; + static constexpr std::string_view MonodroidCategory { "monodroid" }; static constexpr std::string_view AssemblyLoadAnnotation { "Assembly load" }; static constexpr std::string_view ImageLoadAnnotation { "Assembly image load" }; static constexpr std::string_view ClassLoadAnnotation { "Class load" }; static constexpr std::string_view VTableLoadAnnotation { "VTable load" }; - static constexpr std::string_view MethodInvokeAnnotation { "Method invoke" }; - static constexpr std::string_view MethodRunTimeAnnotation { "Method inner run time" }; + static constexpr std::string_view MethodInvokeAnnotation { "Method: invoke" }; + static constexpr std::string_view MethodRunTimeAnnotation { "Method: inner run time" }; static constexpr std::string_view MonitorContentionAnnotation { "Monitor contention" }; + + static constexpr std::string_view XAInitInternal { "XA::InitInternal" }; + }; + + enum class PerfettoTrackId : uint64_t + { + // We need to start high, so that we don't conflict with the standard Perfetto trakck IDs + AssemblyLoad = 0xDEADBEEF, + ClassLoad, + ImageLoad, + MethodInner, + MethodInvoke, + MonitorContention, + VTableLoad, }; } PERFETTO_DEFINE_CATEGORIES ( - perfetto::Category (xamarin::android::PerfettoConstants::ManagedRuntimeCategory.data ()).SetDescription ("Events from the MonoVM runtime") + perfetto::Category (xamarin::android::PerfettoConstants::MonoRuntimeCategory.data ()).SetDescription ("Events from the MonoVM runtime"), + perfetto::Category (xamarin::android::PerfettoConstants::MonodroidCategory.data ()).SetDescription ("Events from the .NET Android native runtime") ); namespace xamarin::android { @@ -54,54 +70,79 @@ namespace xamarin::android { class PerfettoSupport { - force_inline static void set_desc_name (perfetto::protos::gen::TrackDescriptor &desc, const char *name) noexcept - { - if (name == nullptr) { - return; - } - desc.set_name (name); - } + static constexpr std::string_view Unnamed_AnnotationName { "Unnamed annotation" }; + static constexpr std::string_view AssemblyName_AnnotationName { "Assembly name" }; + static constexpr std::string_view ImageName_AnnotationName { "Image name" }; + static constexpr std::string_view MethodName_AnnotationName { "Method name" }; + + static constexpr std::string_view Null_AnnotationContent { "" }; + static constexpr std::string_view MissingMethodName { "" }; public: - template - force_inline static uint64_t get_track_id (TMonoType *data) + template + force_inline static perfetto::Track get_name_annotated_track () { - return reinterpret_cast(data); + auto track = perfetto::Track (static_cast(TTrack), perfetto::ThreadTrack::Current ()); + auto desc = track.Serialize (); + + if constexpr (TTrack == PerfettoTrackId::AssemblyLoad) { + desc.set_name (PerfettoConstants::AssemblyLoadAnnotation.data ()); + } else if constexpr (TTrack == PerfettoTrackId::ImageLoad) { + desc.set_name (PerfettoConstants::ImageLoadAnnotation.data ()); + } else if constexpr (TTrack == PerfettoTrackId::ClassLoad) { + desc.set_name (PerfettoConstants::ClassLoadAnnotation.data ()); + } else if constexpr (TTrack == PerfettoTrackId::VTableLoad) { + desc.set_name (PerfettoConstants::VTableLoadAnnotation.data ()); + } else if constexpr (TTrack == PerfettoTrackId::MethodInvoke) { + desc.set_name (PerfettoConstants::MethodInvokeAnnotation.data ()); + } else if constexpr (TTrack == PerfettoTrackId::MethodInner) { + desc.set_name (PerfettoConstants::MethodRunTimeAnnotation.data ()); + } else if constexpr (TTrack == PerfettoTrackId::MonitorContention) { + desc.set_name (PerfettoConstants::MonitorContentionAnnotation.data ()); + } + set_track_event_descriptor (track, desc); + return track; } template - force_inline static perfetto::Track get_name_annotated_track (TMonoType *data) + force_inline static void add_name_annotation (perfetto::EventContext &ctx, TMonoType *data) { - auto track = perfetto::Track::FromPointer (data, perfetto::ThreadTrack::Current ()); - auto desc = track.Serialize (); + std::string name{}; + const std::string_view *annotation_name = nullptr; - if constexpr (std::is_same_v) { + if constexpr (std::same_as) { + annotation_name = &AssemblyName_AnnotationName; MonoAssemblyName *asm_name = mono_assembly_get_name (data); - set_desc_name (desc, asm_name == nullptr ? nullptr : mono_assembly_name_get_name (asm_name)); - } else if constexpr (std::is_same_v) { - set_desc_name (desc, mono_image_get_name (data)); - } else if constexpr (std::is_same_v) { - std::string name{}; - append_full_class_name (data, name); - desc.set_name (name); - } else if constexpr (std::is_same_v) { - return get_name_annotated_track (mono_vtable_class (data)); - } else if constexpr (std::is_same_v) { - std::string name{}; + if (asm_name != nullptr) [[likely]] { + name = mono_assembly_name_get_name (asm_name); + } + } else if constexpr (std::same_as ) { + annotation_name = &ImageName_AnnotationName; + name = mono_image_get_name (data); + } else if constexpr (std::same_as ) { + annotation_name = &MethodName_AnnotationName; append_full_class_name (mono_method_get_class (data), name); name.append ("."); - name.append (mono_method_get_name (data)); - desc.set_name (name); - } else if constexpr (std::is_same_v) { - return get_name_annotated_track (mono_object_get_class (data)); + + const char *method_name = mono_method_get_name (data); + if (method_name != nullptr) [[likely]] { + name.append (method_name); + } else { + name.append (MissingMethodName); + } } - set_track_event_descriptor (track, desc); - return track; - } + auto annotation = ctx.event ()->add_debug_annotations (); + annotation->set_name (annotation_name == nullptr ? Unnamed_AnnotationName.data () : annotation_name->data ()); + annotation->set_string_value (name.empty () ? Null_AnnotationContent.data () : name); + } private: static void append_full_class_name (const MonoClass *klass, std::string &name) { + if (klass == nullptr) [[unlikely]] { + return; + } + name.append (mono_class_get_namespace (const_cast(klass))); name.append ("."); name.append (mono_class_get_name (const_cast(klass))); From e201598477b098633fdaf50e745cab4ff9de82e8 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 9 May 2024 22:02:48 +0200 Subject: [PATCH 33/49] Some events don't show up and I don't know why --- .../monodroid/monodroid-glue-internal.hh | 14 ++++- src/native/monodroid/monodroid-glue.cc | 58 ++++++++++++------- src/native/shared/perfetto_support.hh | 52 +++++++++++------ 3 files changed, 85 insertions(+), 39 deletions(-) diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index 8a4d747da94..d7c503025a6 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -16,6 +16,10 @@ #include #include +#if defined(PERFETTO_ENABLED) +#include "perfetto_support.hh" +#endif + // NDEBUG causes robin_map.h not to include which, in turn, prevents indirect inclusion of . // conflicts with our std::mutex definition in cppcompat.hh #if !defined (NDEBUG) @@ -205,11 +209,19 @@ namespace xamarin::android::internal char* get_java_class_name_for_TypeManager (jclass klass); void log_traces (JNIEnv *env, TraceKind kind, const char *first_line) noexcept; - private: #if defined(PERFETTO_ENABLED) static void perfetto_init () noexcept; + + private: void perfetto_hook_mono_events () noexcept; + + force_inline static void perfetto_trace_event (std::string_view const& event_name) + { + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT (PerfettoConstants::MonodroidCategory.data (), event_name.data (), track); + } #endif + private: static void mono_log_handler (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); static void mono_log_standard_streams_handler (const char *str, mono_bool is_stdout); diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index 7a73d1d57a1..6ce47453188 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -542,7 +542,7 @@ void MonodroidRuntime::prof_assembly_loading ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::AssemblyLoadAnnotation.data (), track); #endif } @@ -551,7 +551,7 @@ void MonodroidRuntime::prof_assembly_loaded ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { PerfettoSupport::add_name_annotation (ctx, assembly); }); @@ -562,7 +562,7 @@ void MonodroidRuntime::prof_image_loading ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::ImageLoadAnnotation.data (), track); #endif } @@ -571,7 +571,7 @@ void MonodroidRuntime::prof_image_loaded ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { PerfettoSupport::add_name_annotation (ctx, image); }); @@ -582,7 +582,7 @@ void MonodroidRuntime::prof_class_loading ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::ClassLoadAnnotation.data (), track); #endif } @@ -591,8 +591,10 @@ void MonodroidRuntime::prof_class_loaded ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, klass); + }); #endif } @@ -600,7 +602,7 @@ void MonodroidRuntime::prof_vtable_loading ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::VTableLoadAnnotation.data (), track); #endif } @@ -609,8 +611,10 @@ void MonodroidRuntime::prof_vtable_loaded ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, vtable); + }); #endif } @@ -618,7 +622,7 @@ void MonodroidRuntime::prof_method_begin_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MethodInvokeAnnotation.data (), track); #endif } @@ -627,7 +631,7 @@ void MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { PerfettoSupport::add_name_annotation (ctx, method); }); @@ -638,7 +642,7 @@ void MonodroidRuntime::prof_method_enter ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MethodRunTimeAnnotation.data (), track); #endif } @@ -647,7 +651,7 @@ void MonodroidRuntime::prof_method_leave ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { PerfettoSupport::add_name_annotation (ctx, method); }); @@ -658,7 +662,7 @@ void MonodroidRuntime::prof_monitor_contention ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); + auto track = PerfettoSupport::get_name_annotated_track (); TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MonitorContentionAnnotation.data (), track); #endif } @@ -667,14 +671,23 @@ void MonodroidRuntime::prof_monitor_acquired ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept { #if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track); + auto track = PerfettoSupport::get_name_annotated_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, object); + }); #endif } void MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] dynamic_local_string& runtime_args) { +#if defined(PERFETTO_ENABLED) + TRACE_EVENT( + PerfettoConstants::MonoRuntimeCategory.data (), + "mono_runtime_init", + PerfettoSupport::get_name_annotated_track () + ); +#endif #if defined (DEBUG) RuntimeOptions options{}; int64_t cur_time; @@ -1749,9 +1762,11 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl jboolean haveSplitApks) { #if defined(PERFETTO_ENABLED) - perfetto_init (); - - TRACE_EVENT (PerfettoConstants::MonodroidCategory.data (), PerfettoConstants::XAInitInternal.data ()); + TRACE_EVENT( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoConstants::XAInitInternal.data (), + PerfettoSupport::get_name_annotated_track () + ); #endif char *mono_log_mask_raw = nullptr; char *mono_log_level_raw = nullptr; @@ -1925,6 +1940,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM *vm, void *reserved) { Util::initialize (); +#if defined(PERFETTO_ENABLED) + MonodroidRuntime::perfetto_init (); +#endif return monodroidRuntime.Java_JNI_OnLoad (vm, reserved); } diff --git a/src/native/shared/perfetto_support.hh b/src/native/shared/perfetto_support.hh index 5fee1a59d01..32429eef800 100644 --- a/src/native/shared/perfetto_support.hh +++ b/src/native/shared/perfetto_support.hh @@ -33,20 +33,23 @@ namespace xamarin::android { static constexpr std::string_view MethodInvokeAnnotation { "Method: invoke" }; static constexpr std::string_view MethodRunTimeAnnotation { "Method: inner run time" }; static constexpr std::string_view MonitorContentionAnnotation { "Monitor contention" }; + static constexpr std::string_view MonodroidRuntimeTrack { "Monodroid" }; - static constexpr std::string_view XAInitInternal { "XA::InitInternal" }; + static constexpr std::string_view XAInitInternal { "InitInternal" }; }; enum class PerfettoTrackId : uint64_t { // We need to start high, so that we don't conflict with the standard Perfetto trakck IDs - AssemblyLoad = 0xDEADBEEF, - ClassLoad, - ImageLoad, - MethodInner, - MethodInvoke, - MonitorContention, - VTableLoad, + AssemblyLoadMonoVM = 0xDEADBEEF, + ClassLoadMonoVM, + ImageLoadMonoVM, + MethodInnerMonoVM, + MethodInvokeMonoVM, + MonitorContentionMonoVM, + VTableLoadMonoVM, + + MonodroidRuntime, }; } @@ -74,6 +77,7 @@ namespace xamarin::android { static constexpr std::string_view AssemblyName_AnnotationName { "Assembly name" }; static constexpr std::string_view ImageName_AnnotationName { "Image name" }; static constexpr std::string_view MethodName_AnnotationName { "Method name" }; + static constexpr std::string_view ClassName_AnnotationName { "Class name" }; static constexpr std::string_view Null_AnnotationContent { "" }; static constexpr std::string_view MissingMethodName { "" }; @@ -82,24 +86,27 @@ namespace xamarin::android { template force_inline static perfetto::Track get_name_annotated_track () { - auto track = perfetto::Track (static_cast(TTrack), perfetto::ThreadTrack::Current ()); + auto track = perfetto::Track (static_cast(TTrack), perfetto::ProcessTrack::Current ()); auto desc = track.Serialize (); - if constexpr (TTrack == PerfettoTrackId::AssemblyLoad) { + if constexpr (TTrack == PerfettoTrackId::AssemblyLoadMonoVM) { desc.set_name (PerfettoConstants::AssemblyLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::ImageLoad) { + } else if constexpr (TTrack == PerfettoTrackId::ImageLoadMonoVM) { desc.set_name (PerfettoConstants::ImageLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::ClassLoad) { + } else if constexpr (TTrack == PerfettoTrackId::ClassLoadMonoVM) { desc.set_name (PerfettoConstants::ClassLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::VTableLoad) { + } else if constexpr (TTrack == PerfettoTrackId::VTableLoadMonoVM) { desc.set_name (PerfettoConstants::VTableLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::MethodInvoke) { + } else if constexpr (TTrack == PerfettoTrackId::MethodInvokeMonoVM) { desc.set_name (PerfettoConstants::MethodInvokeAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::MethodInner) { + } else if constexpr (TTrack == PerfettoTrackId::MethodInnerMonoVM) { desc.set_name (PerfettoConstants::MethodRunTimeAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::MonitorContention) { + } else if constexpr (TTrack == PerfettoTrackId::MonitorContentionMonoVM) { desc.set_name (PerfettoConstants::MonitorContentionAnnotation.data ()); + } else if constexpr (TTrack == PerfettoTrackId::MonodroidRuntime) { + desc.set_name (PerfettoConstants::MonodroidRuntimeTrack.data ()); } + set_track_event_descriptor (track, desc); return track; } @@ -116,10 +123,10 @@ namespace xamarin::android { if (asm_name != nullptr) [[likely]] { name = mono_assembly_name_get_name (asm_name); } - } else if constexpr (std::same_as ) { + } else if constexpr (std::same_as) { annotation_name = &ImageName_AnnotationName; name = mono_image_get_name (data); - } else if constexpr (std::same_as ) { + } else if constexpr (std::same_as) { annotation_name = &MethodName_AnnotationName; append_full_class_name (mono_method_get_class (data), name); name.append ("."); @@ -130,6 +137,15 @@ namespace xamarin::android { } else { name.append (MissingMethodName); } + } else if constexpr (std::same_as) { + annotation_name = &ClassName_AnnotationName; + append_full_class_name (data, name); + } else if constexpr (std::same_as) { + annotation_name = &ClassName_AnnotationName; + append_full_class_name (mono_vtable_class (data), name); + } else if constexpr (std::same_as) { + annotation_name = &ClassName_AnnotationName; + append_full_class_name (mono_object_get_class (data), name); } auto annotation = ctx.event ()->add_debug_annotations (); From acd70e33bdf0faf6b78fc2b0ffb0f591c4364562 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 10 May 2024 19:21:25 +0200 Subject: [PATCH 34/49] Trying to figure out why some events aren't recorded --- external/perfetto | 2 +- src/native/monodroid/CMakeLists.txt | 1 + .../monodroid/monodroid-glue-internal.hh | 6 - src/native/monodroid/monodroid-glue.cc | 165 ++-------------- src/native/monodroid/monodroid-profiling.cc | 187 ++++++++++++++++++ src/native/shared/perfetto_support.hh | 58 ++++-- 6 files changed, 249 insertions(+), 170 deletions(-) create mode 100644 src/native/monodroid/monodroid-profiling.cc diff --git a/external/perfetto b/external/perfetto index eb5ef24c58d..7add4fded39 160000 --- a/external/perfetto +++ b/external/perfetto @@ -1 +1 @@ -Subproject commit eb5ef24c58d13cec289d733d03f0f3f0ed321b12 +Subproject commit 7add4fded398ef47414a556b7b81d212a4482a66 diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index d4f44be90bf..f2afda8fb84 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -54,6 +54,7 @@ list(APPEND XAMARIN_MONODROID_COMMON_SOURCES mono-log-adapter.cc monodroid-glue.cc monodroid-networkinfo.cc + monodroid-profiling.cc monodroid-tracing.cc monovm-properties.cc osbridge.cc diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index d7c503025a6..cdb1c42fa70 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -214,12 +214,6 @@ namespace xamarin::android::internal private: void perfetto_hook_mono_events () noexcept; - - force_inline static void perfetto_trace_event (std::string_view const& event_name) - { - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT (PerfettoConstants::MonodroidCategory.data (), event_name.data (), track); - } #endif private: static void mono_log_handler (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index 6ce47453188..17d919743b2 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -98,7 +98,7 @@ bool MonodroidRuntime::startup_in_progress = true; void MonodroidRuntime::thread_start ([[maybe_unused]] MonoProfiler *prof, [[maybe_unused]] uintptr_t tid) { - JNIEnv* env; + JNIEnv* env = nullptr; int r = osBridge.get_jvm ()->AttachCurrentThread (&env, nullptr); if (r != JNI_OK) { @@ -112,6 +112,10 @@ MonodroidRuntime::thread_start ([[maybe_unused]] MonoProfiler *prof, [[maybe_unu void MonodroidRuntime::thread_end ([[maybe_unused]] MonoProfiler *prof, [[maybe_unused]] uintptr_t tid) { +#if defined(PERFETTO_ENABLED) + perfetto::TrackEvent::Flush (); +#endif + int r = osBridge.get_jvm ()->DetachCurrentThread (); if (r != JNI_OK) { #if DEBUG @@ -538,154 +542,15 @@ MonodroidRuntime::set_debug_options (void) mono_debug_init (MONO_DEBUG_FORMAT_MONO); } -void -MonodroidRuntime::prof_assembly_loading ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::AssemblyLoadAnnotation.data (), track); -#endif -} - -void -MonodroidRuntime::prof_assembly_loaded ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { - PerfettoSupport::add_name_annotation (ctx, assembly); - }); -#endif -} - -void -MonodroidRuntime::prof_image_loading ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::ImageLoadAnnotation.data (), track); -#endif -} - -void -MonodroidRuntime::prof_image_loaded ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { - PerfettoSupport::add_name_annotation (ctx, image); - }); -#endif -} - -void -MonodroidRuntime::prof_class_loading ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::ClassLoadAnnotation.data (), track); -#endif -} - -void -MonodroidRuntime::prof_class_loaded ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { - PerfettoSupport::add_name_annotation (ctx, klass); - }); -#endif -} - -void -MonodroidRuntime::prof_vtable_loading ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::VTableLoadAnnotation.data (), track); -#endif -} - -void -MonodroidRuntime::prof_vtable_loaded ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { - PerfettoSupport::add_name_annotation (ctx, vtable); - }); -#endif -} - -void -MonodroidRuntime::prof_method_begin_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MethodInvokeAnnotation.data (), track); -#endif -} - -void -MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { - PerfettoSupport::add_name_annotation (ctx, method); - }); -#endif -} - -void -MonodroidRuntime::prof_method_enter ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MethodRunTimeAnnotation.data (), track); -#endif -} - -void -MonodroidRuntime::prof_method_leave ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { - PerfettoSupport::add_name_annotation (ctx, method); - }); -#endif -} - -void -MonodroidRuntime::prof_monitor_contention ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_BEGIN (PerfettoConstants::MonoRuntimeCategory.data (), PerfettoConstants::MonitorContentionAnnotation.data (), track); -#endif -} - -void -MonodroidRuntime::prof_monitor_acquired ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept -{ -#if defined(PERFETTO_ENABLED) - auto track = PerfettoSupport::get_name_annotated_track (); - TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { - PerfettoSupport::add_name_annotation (ctx, object); - }); -#endif -} - void MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] dynamic_local_string& runtime_args) { #if defined(PERFETTO_ENABLED) + log_info (LOG_DEFAULT, "Trace event for mono_runtime_init"); TRACE_EVENT( PerfettoConstants::MonoRuntimeCategory.data (), "mono_runtime_init", - PerfettoSupport::get_name_annotated_track () + PerfettoSupport::get_name_annotated_thread_track () ); #endif #if defined (DEBUG) @@ -1764,8 +1629,8 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl #if defined(PERFETTO_ENABLED) TRACE_EVENT( PerfettoConstants::MonoRuntimeCategory.data (), - PerfettoConstants::XAInitInternal.data (), - PerfettoSupport::get_name_annotated_track () + "initInternal", + PerfettoSupport::get_name_annotated_thread_track () ); #endif char *mono_log_mask_raw = nullptr; @@ -1894,7 +1759,13 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl } mono_runtime_init (env, runtime_args); - +#if defined(PERFETTO_ENABLED) + TRACE_EVENT( + PerfettoConstants::MonoRuntimeCategory.data (), + "initInternal_2", + PerfettoSupport::get_name_annotated_thread_track () + ); +#endif if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (mono_runtime_init_index); } @@ -1934,6 +1805,10 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl } #endif // def RELEASE && def ANDROID && def NET startup_in_progress = false; + +#if defined(PERFETTO_ENABLED) + perfetto::TrackEvent::Flush (); +#endif } JNIEXPORT jint JNICALL diff --git a/src/native/monodroid/monodroid-profiling.cc b/src/native/monodroid/monodroid-profiling.cc new file mode 100644 index 00000000000..de3286b18e8 --- /dev/null +++ b/src/native/monodroid/monodroid-profiling.cc @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (PERFETTO_ENABLED) +#include +#include "perfetto_support.hh" +#endif + +#include "monodroid-glue-internal.hh" + +using namespace xamarin::android; +using namespace xamarin::android::internal; + +void +MonodroidRuntime::prof_assembly_loading ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_BEGIN ( + PerfettoConstants::MonoRuntimeCategory.data(), + PerfettoSupport::get_event_name (PerfettoConstants::AssemblyLoadAnnotation), track + ); +#endif +} + +void +MonodroidRuntime::prof_assembly_loaded ([[maybe_unused]] MonoProfiler *prof, MonoAssembly *assembly) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, assembly); + }); +#endif +} + +void +MonodroidRuntime::prof_image_loading ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_BEGIN ( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_event_name (PerfettoConstants::ImageLoadAnnotation), + track + ); +#endif +} + +void +MonodroidRuntime::prof_image_loaded ([[maybe_unused]] MonoProfiler *prof, MonoImage *image) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, image); + }); +#endif +} + +void +MonodroidRuntime::prof_class_loading ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_BEGIN ( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_event_name (PerfettoConstants::ClassLoadAnnotation), + track + ); +#endif +} + +void +MonodroidRuntime::prof_class_loaded ([[maybe_unused]] MonoProfiler *prof, MonoClass *klass) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, klass); + }); +#endif +} + +void +MonodroidRuntime::prof_vtable_loading ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_BEGIN ( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_event_name (PerfettoConstants::VTableLoadAnnotation), + track + ); +#endif +} + +void +MonodroidRuntime::prof_vtable_loaded ([[maybe_unused]] MonoProfiler *prof, MonoVTable *vtable) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, vtable); + }); +#endif +} + +void +MonodroidRuntime::prof_method_begin_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_BEGIN ( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_event_name (PerfettoConstants::MethodInvokeAnnotation), + track + ); +#endif +} + +void +MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, method); + }); +#endif +} + +void +MonodroidRuntime::prof_method_enter ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_BEGIN ( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_event_name (PerfettoConstants::MethodRunTimeAnnotation), + track + ); +#endif +} + +void +MonodroidRuntime::prof_method_leave ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, method); + }); +#endif +} + +void +MonodroidRuntime::prof_monitor_contention ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_BEGIN ( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_event_name (PerfettoConstants::MonitorContentionAnnotation), + track + ); +#endif +} + +void +MonodroidRuntime::prof_monitor_acquired ([[maybe_unused]] MonoProfiler *prof, MonoObject *object) noexcept +{ +#if defined(PERFETTO_ENABLED) + auto track = PerfettoSupport::get_name_annotated_thread_track (); + TRACE_EVENT_END (PerfettoConstants::MonoRuntimeCategory.data (), track, [&](perfetto::EventContext ctx) { + PerfettoSupport::add_name_annotation (ctx, object); + }); +#endif +} diff --git a/src/native/shared/perfetto_support.hh b/src/native/shared/perfetto_support.hh index 32429eef800..89dd9d19380 100644 --- a/src/native/shared/perfetto_support.hh +++ b/src/native/shared/perfetto_support.hh @@ -3,6 +3,7 @@ #if defined(PERFETTO_ENABLED) #include +#include #include #include @@ -83,34 +84,55 @@ namespace xamarin::android { static constexpr std::string_view MissingMethodName { "" }; public: - template + + force_inline constexpr static perfetto::StaticString get_event_name (std::string_view const& sv) + { + return perfetto::StaticString { sv.data () }; + } + + template force_inline static perfetto::Track get_name_annotated_track () { - auto track = perfetto::Track (static_cast(TTrack), perfetto::ProcessTrack::Current ()); + using TParentTrack = std::conditional_t; + auto track = perfetto::Track (static_cast(PerfettoTrackId::MonodroidRuntime)); auto desc = track.Serialize (); - if constexpr (TTrack == PerfettoTrackId::AssemblyLoadMonoVM) { - desc.set_name (PerfettoConstants::AssemblyLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::ImageLoadMonoVM) { - desc.set_name (PerfettoConstants::ImageLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::ClassLoadMonoVM) { - desc.set_name (PerfettoConstants::ClassLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::VTableLoadMonoVM) { - desc.set_name (PerfettoConstants::VTableLoadAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::MethodInvokeMonoVM) { - desc.set_name (PerfettoConstants::MethodInvokeAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::MethodInnerMonoVM) { - desc.set_name (PerfettoConstants::MethodRunTimeAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::MonitorContentionMonoVM) { - desc.set_name (PerfettoConstants::MonitorContentionAnnotation.data ()); - } else if constexpr (TTrack == PerfettoTrackId::MonodroidRuntime) { + // if constexpr (TTrack == PerfettoTrackId::AssemblyLoadMonoVM) { + // desc.set_name (PerfettoConstants::AssemblyLoadAnnotation.data ()); + // } else if constexpr (TTrack == PerfettoTrackId::ImageLoadMonoVM) { + // desc.set_name (PerfettoConstants::ImageLoadAnnotation.data ()); + // } else if constexpr (TTrack == PerfettoTrackId::ClassLoadMonoVM) { + // desc.set_name (PerfettoConstants::ClassLoadAnnotation.data ()); + // } else if constexpr (TTrack == PerfettoTrackId::VTableLoadMonoVM) { + // desc.set_name (PerfettoConstants::VTableLoadAnnotation.data ()); + // } else if constexpr (TTrack == PerfettoTrackId::MethodInvokeMonoVM) { + // desc.set_name (PerfettoConstants::MethodInvokeAnnotation.data ()); + // } else if constexpr (TTrack == PerfettoTrackId::MethodInnerMonoVM) { + // desc.set_name (PerfettoConstants::MethodRunTimeAnnotation.data ()); + // } else if constexpr (TTrack == PerfettoTrackId::MonitorContentionMonoVM) { + // desc.set_name (PerfettoConstants::MonitorContentionAnnotation.data ()); + // } else if constexpr (TTrack == PerfettoTrackId::MonodroidRuntime) { desc.set_name (PerfettoConstants::MonodroidRuntimeTrack.data ()); - } + //} set_track_event_descriptor (track, desc); return track; } + template + [[gnu::flatten]] + force_inline static perfetto::Track get_name_annotated_process_track () + { + return get_name_annotated_track (); + } + + template + [[gnu::flatten]] + force_inline static perfetto::Track get_name_annotated_thread_track () + { + return get_name_annotated_track (); + } + template force_inline static void add_name_annotation (perfetto::EventContext &ctx, TMonoType *data) { From 7060c43c54d8eb832e4535e06a923f4817ceb29f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 13 May 2024 17:44:31 +0200 Subject: [PATCH 35/49] Add some configuration options Still can't figure out why some events show up in the trace only once, during first session after device reboot. --- .../monodroid/monodroid-glue-internal.hh | 4 + src/native/monodroid/monodroid-glue.cc | 104 ++++++++++++------ src/native/monodroid/monodroid-profiling.hh | 14 +++ src/native/monodroid/timing-internal.cc | 52 +++++++++ src/native/monodroid/timing-internal.hh | 24 +++- src/native/runtime-base/shared-constants.hh | 10 ++ src/native/runtime-base/strings.hh | 20 ++++ src/native/shared/perfetto_support.hh | 4 +- 8 files changed, 196 insertions(+), 36 deletions(-) create mode 100644 src/native/monodroid/monodroid-profiling.hh diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index cdb1c42fa70..c6d28d9b70a 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -268,6 +268,10 @@ namespace xamarin::android::internal void set_debug_options (); void parse_gdb_options (); void mono_runtime_init (JNIEnv *env, dynamic_local_string& runtime_args); + void timing_init () noexcept; + void timing_init_extended () noexcept; + void timing_init_verbose () noexcept; + void timing_init_extreme () noexcept; void init_android_runtime (JNIEnv *env, jclass runtimeClass, jobject loader); void set_environment_variable_for_directory (const char *name, jstring_wrapper &value, bool createDirectory, mode_t mode); diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index 17d919743b2..ec0fea34716 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -61,10 +61,10 @@ #include "embedded-assemblies.hh" #include "monodroid-glue.hh" #include "monodroid-glue-internal.hh" +#include "monodroid-profiling.hh" #include "globals.hh" #include "xamarin-app.hh" #include "timing.hh" -//#include "xa-internal-api-impl.hh" #include "build-info.hh" #include "monovm-properties.hh" #include "startup-aware-lock.hh" @@ -72,8 +72,6 @@ #include "search.hh" #include "runtime-util.hh" -//#include "xamarin_getifaddrs.h" - #include "cpp-util.hh" #include "strings.hh" @@ -547,7 +545,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse { #if defined(PERFETTO_ENABLED) log_info (LOG_DEFAULT, "Trace event for mono_runtime_init"); - TRACE_EVENT( + TRACE_EVENT_BEGIN( PerfettoConstants::MonoRuntimeCategory.data (), "mono_runtime_init", PerfettoSupport::get_name_annotated_thread_track () @@ -667,12 +665,6 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse Util::set_world_accessable (jit_log_path.get ()); } - profiler_handle = mono_profiler_create (nullptr); - mono_profiler_set_thread_started_callback (profiler_handle, thread_start); - mono_profiler_set_thread_stopped_callback (profiler_handle, thread_end); -#if defined (PERFETTO_ENABLED) - perfetto_hook_mono_events (); -#endif if (log_methods) [[unlikely]]{ jit_time.mark_start (); mono_profiler_set_jit_begin_callback (profiler_handle, jit_begin); @@ -729,6 +721,13 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse xamarin_app_init (env, get_function_pointer_at_startup); } #endif // def RELEASE && def ANDROID && def NET + +#if defined(PERFETTO_ENABLED) + TRACE_EVENT_END( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_name_annotated_thread_track () + ); +#endif } void @@ -1584,41 +1583,77 @@ MonodroidRuntime::install_logging_handlers () void MonodroidRuntime::perfetto_init () noexcept { - log_warn (LOG_TIMING, "INIT perfetto"); perfetto::TracingInitArgs args; args.backends = perfetto::kSystemBackend; perfetto::Tracing::Initialize (args); perfetto::TrackEvent::Register (); } +#endif // def PERFETTO_ENABLED void -MonodroidRuntime::perfetto_hook_mono_events () noexcept +MonodroidRuntime::timing_init_extended () noexcept { - if (profiler_handle == nullptr) { - return; - } - - log_warn (LOG_TIMING, "HOOK perfetto"); mono_profiler_set_assembly_loading_callback (profiler_handle, prof_assembly_loading); mono_profiler_set_assembly_loaded_callback (profiler_handle, prof_assembly_loaded); - mono_profiler_set_image_loading_callback (profiler_handle, prof_image_loading); - mono_profiler_set_image_loaded_callback (profiler_handle, prof_image_loaded); mono_profiler_set_class_loading_callback (profiler_handle, prof_class_loading); mono_profiler_set_class_loaded_callback (profiler_handle, prof_class_loaded); - // mono_profiler_set_vtable_loading_callback (profiler_handle, prof_vtable_loading); - // mono_profiler_set_vtable_loaded_callback (profiler_handle, prof_vtable_loaded); - mono_profiler_set_monitor_contention_callback (profiler_handle, prof_monitor_contention); - mono_profiler_set_monitor_acquired_callback (profiler_handle, prof_monitor_acquired); mono_profiler_set_method_begin_invoke_callback (profiler_handle, prof_method_begin_invoke); mono_profiler_set_method_end_invoke_callback (profiler_handle, prof_method_end_invoke); - mono_profiler_set_method_enter_callback (profiler_handle, prof_method_enter); - mono_profiler_set_method_leave_callback (profiler_handle, prof_method_leave); +} + +void +MonodroidRuntime::timing_init_verbose () noexcept +{ + mono_profiler_set_jit_begin_callback (profiler_handle, jit_begin); + mono_profiler_set_jit_done_callback (profiler_handle, jit_done); + mono_profiler_set_jit_failed_callback (profiler_handle, jit_failed); + mono_profiler_set_monitor_contention_callback (profiler_handle, prof_monitor_contention); + mono_profiler_set_monitor_acquired_callback (profiler_handle, prof_monitor_acquired); } + +void +MonodroidRuntime::timing_init_extreme () noexcept +{ + mono_profiler_set_vtable_loading_callback (profiler_handle, prof_vtable_loading); + mono_profiler_set_vtable_loaded_callback (profiler_handle, prof_vtable_loaded); + + mono_profiler_set_image_loading_callback (profiler_handle, prof_image_loading); + mono_profiler_set_image_loaded_callback (profiler_handle, prof_image_loaded); +} + +[[gnu::flatten]] void +MonodroidRuntime::timing_init () noexcept +{ +#if !defined(PERFETTO_ENABLED) + if (!FastTiming::enabled () || FastTiming::mode () == ProfilingMode::Bare) { + return; + } +#endif + switch (FastTiming::mode ()) { + case ProfilingMode::Extreme: + timing_init_extreme (); + [[fallthrough]]; + + case ProfilingMode::Verbose: + timing_init_verbose (); + [[fallthrough]]; + +#if defined(PERFETTO_ENABLED) + case ProfilingMode::Bare: #endif + case ProfilingMode::Extended: + timing_init_extended (); + break; + + default: + // ignored + break; + } +} inline void MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, @@ -1627,7 +1662,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl jboolean haveSplitApks) { #if defined(PERFETTO_ENABLED) - TRACE_EVENT( + TRACE_EVENT_BEGIN( PerfettoConstants::MonoRuntimeCategory.data (), "initInternal", PerfettoSupport::get_name_annotated_thread_track () @@ -1644,6 +1679,11 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl // If fast logging is disabled, log messages immediately FastTiming::initialize ((Logger::log_timing_categories() & LogTimingCategories::FastBare) != LogTimingCategories::FastBare); + profiler_handle = mono_profiler_create (nullptr); + mono_profiler_set_thread_started_callback (profiler_handle, thread_start); + mono_profiler_set_thread_stopped_callback (profiler_handle, thread_end); + timing_init (); + size_t total_time_index; if (FastTiming::enabled ()) [[unlikely]] { timing = new Timing (); @@ -1759,13 +1799,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl } mono_runtime_init (env, runtime_args); -#if defined(PERFETTO_ENABLED) - TRACE_EVENT( - PerfettoConstants::MonoRuntimeCategory.data (), - "initInternal_2", - PerfettoSupport::get_name_annotated_thread_track () - ); -#endif + if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (mono_runtime_init_index); } @@ -1807,6 +1841,10 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl startup_in_progress = false; #if defined(PERFETTO_ENABLED) + TRACE_EVENT_END( + PerfettoConstants::MonoRuntimeCategory.data (), + PerfettoSupport::get_name_annotated_thread_track () + ); perfetto::TrackEvent::Flush (); #endif } diff --git a/src/native/monodroid/monodroid-profiling.hh b/src/native/monodroid/monodroid-profiling.hh new file mode 100644 index 00000000000..0aa4a4a04e8 --- /dev/null +++ b/src/native/monodroid/monodroid-profiling.hh @@ -0,0 +1,14 @@ +#if !defined(MONODROID_PROFILING_HH) +#define MONODROID_PROFILING_HH + +namespace xamarin::android { + // Keep the values ordered in the order of increasing verbosity + enum class ProfilingMode + { + Bare, + Extended, + Verbose, + Extreme, + }; +} +#endif // MONODROID_PROFILING_HH diff --git a/src/native/monodroid/timing-internal.cc b/src/native/monodroid/timing-internal.cc index 5b91c5186f8..acb0cb9b93e 100644 --- a/src/native/monodroid/timing-internal.cc +++ b/src/native/monodroid/timing-internal.cc @@ -12,6 +12,46 @@ bool FastTiming::is_enabled = false; bool FastTiming::immediate_logging = false; TimingEvent FastTiming::init_time {}; +void +FastTiming::parse_options (dynamic_local_string const& value) noexcept +{ + if (value.empty ()) { + return; + } + + string_segment param; + while (value.next_token (',', param)) { + if (param.starts_with (OPT_MODE)) { + if (param.equal (OPT_MODE.length (), OPT_MODE_BARE)) { + profiling_mode = ProfilingMode::Bare; + continue; + } + + if (param.equal (OPT_MODE.length (), OPT_MODE_EXTENDED)) { + profiling_mode = ProfilingMode::Extended; + continue; + } + + if (param.equal (OPT_MODE.length (), OPT_MODE_VERBOSE)) { + profiling_mode = ProfilingMode::Verbose; + continue; + } + + if (param.equal (OPT_MODE.length (), OPT_MODE_EXTREME)) { + profiling_mode = ProfilingMode::Extreme; + continue; + } + } + } + +#if defined(PERFETTO_ENABLED) + // Clamp the profiling mode to extended, otherwise using Perfetto makes no sense + if (profiling_mode < ProfilingMode::Extended) { + profiling_mode = ProfilingMode::Extended; + } +#endif +} + void FastTiming::really_initialize (bool log_immediately) noexcept { @@ -19,6 +59,18 @@ FastTiming::really_initialize (bool log_immediately) noexcept is_enabled = true; immediate_logging = log_immediately; + dynamic_local_string value; + int prop_len = 0; + + if constexpr (SharedConstants::PerfettoEnabled) { + prop_len = AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_PERFETTO, value); + } + + if (prop_len <= 0) { + AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_TIMING, value); + } + parse_options (value); + if (immediate_logging) { return; } diff --git a/src/native/monodroid/timing-internal.hh b/src/native/monodroid/timing-internal.hh index 519b98cb28e..dc223931463 100644 --- a/src/native/monodroid/timing-internal.hh +++ b/src/native/monodroid/timing-internal.hh @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "cpp-util.hh" @@ -11,6 +12,7 @@ #include "startup-aware-lock.hh" #include "strings.hh" #include "util.hh" +#include "monodroid-profiling.hh" #include "shared-constants.hh" namespace xamarin::android::internal @@ -37,7 +39,7 @@ namespace xamarin::android::internal RuntimeConfigBlob = 9, RuntimeRegister = 10, TotalRuntimeInit = 11, - Unspecified = 12, + Unspecified = std::numeric_limits>::max (), }; struct TimingEventPoint @@ -86,6 +88,19 @@ namespace xamarin::android::internal static constexpr uint32_t ms_in_second = 1000; static constexpr uint32_t ns_in_second = ms_in_second * ns_in_millisecond; + // Defaults +#if defined(PERFETTO_ENABLED) + static constexpr ProfilingMode default_profiling_mode = ProfilingMode::Extended; +#else + static constexpr ProfilingMode default_profiling_mode = ProfilingMode::Bare; +#endif + // Parameters in the debug.mono.{timing,perfetto} properties + static constexpr std::string_view OPT_MODE { "mode=" }; + static constexpr std::string_view OPT_MODE_BARE { "bare" }; + static constexpr std::string_view OPT_MODE_EXTENDED { "extended" }; + static constexpr std::string_view OPT_MODE_VERBOSE { "verbose" }; + static constexpr std::string_view OPT_MODE_EXTREME { "extreme" }; + protected: FastTiming () noexcept { @@ -93,6 +108,11 @@ namespace xamarin::android::internal } public: + force_inline static ProfilingMode mode () noexcept + { + return profiling_mode; + } + force_inline static bool enabled () noexcept { return is_enabled; @@ -235,6 +255,7 @@ namespace xamarin::android::internal private: static void really_initialize (bool log_immediately) noexcept; + static void parse_options (dynamic_local_string const& value) noexcept; static void* timing_signal_thread (void *arg) noexcept; force_inline static void mark (TimingEventPoint &point) noexcept @@ -446,6 +467,7 @@ namespace xamarin::android::internal static TimingEvent init_time; static bool is_enabled; static bool immediate_logging; + static inline ProfilingMode profiling_mode = default_profiling_mode; }; extern FastTiming *internal_timing; diff --git a/src/native/runtime-base/shared-constants.hh b/src/native/runtime-base/shared-constants.hh index bc8461f59f0..f7943528ba1 100644 --- a/src/native/runtime-base/shared-constants.hh +++ b/src/native/runtime-base/shared-constants.hh @@ -18,6 +18,12 @@ namespace xamarin::android::internal class SharedConstants { public: +#if defined(PERFETTO_ENABLED) + static constexpr bool PerfettoEnabled = true; +#else + static constexpr bool PerfettoEnabled = false; +#endif + // These three MUST be the same as like-named constants in src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.Basic.cs static constexpr std::string_view MANGLED_ASSEMBLY_NAME_EXT { ".so" }; static constexpr std::string_view MANGLED_ASSEMBLY_REGULAR_ASSEMBLY_MARKER { "lib_" }; @@ -55,9 +61,13 @@ namespace xamarin::android::internal 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" }; + + // An alias to `debug.mono.timing` + static inline constexpr std::string_view DEBUG_MONO_PERFETTO { "debug.mono.perfetto" }; 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_TIMING { "debug.mono.timing" }; 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" }; diff --git a/src/native/runtime-base/strings.hh b/src/native/runtime-base/strings.hh index a552abd345c..b600143a1f9 100644 --- a/src/native/runtime-base/strings.hh +++ b/src/native/runtime-base/strings.hh @@ -47,6 +47,26 @@ namespace xamarin::android::internal return length () == 0; } + force_inline bool equal (size_t start_index, std::string_view const& s) const noexcept + { + if (s.empty ()) { + return false; + } + + if (!can_access (s.length () + start_index)) { + return false; + } + + if (s.length () != length () - start_index) { + return false; + } + + if (length () == 0) { + return true; + } + return memcmp (_start + start_index, s.data (), length () - start_index) == 0; + } + force_inline bool equal (const char *s) const noexcept { if (s == nullptr) diff --git a/src/native/shared/perfetto_support.hh b/src/native/shared/perfetto_support.hh index 89dd9d19380..43566f8a400 100644 --- a/src/native/shared/perfetto_support.hh +++ b/src/native/shared/perfetto_support.hh @@ -93,8 +93,8 @@ namespace xamarin::android { template force_inline static perfetto::Track get_name_annotated_track () { - using TParentTrack = std::conditional_t; - auto track = perfetto::Track (static_cast(PerfettoTrackId::MonodroidRuntime)); + using TParentTrack = std::conditional_t; + auto track = perfetto::Track (static_cast(PerfettoTrackId::MonodroidRuntime), TParentTrack::Current ()); auto desc = track.Serialize (); // if constexpr (TTrack == PerfettoTrackId::AssemblyLoadMonoVM) { From 59290b340242e68235019496a3bb6567748212e2 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 May 2024 18:44:18 +0200 Subject: [PATCH 36/49] Post-merge fixups --- build-tools/cmake/xa_preamble.cmake | 7 -- src/native/CMakeLists.txt | 21 +---- src/native/CMakePresets.json.in | 55 ------------- src/native/monodroid/CMakeLists.txt | 118 +--------------------------- src/native/runtime-base/util.hh | 3 - src/native/shared/CMakeLists.txt | 6 -- 6 files changed, 3 insertions(+), 207 deletions(-) delete mode 100644 build-tools/cmake/xa_preamble.cmake diff --git a/build-tools/cmake/xa_preamble.cmake b/build-tools/cmake/xa_preamble.cmake deleted file mode 100644 index d28fc5e10c4..00000000000 --- a/build-tools/cmake/xa_preamble.cmake +++ /dev/null @@ -1,7 +0,0 @@ -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) - -# -# 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}") diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 3c26bdfa859..2c4dd5bbe5c 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -63,18 +63,13 @@ endif() option(ENABLE_CLANG_ASAN "Enable the clang AddressSanitizer support" OFF) option(ENABLE_CLANG_UBSAN "Enable the clang UndefinedBehaviorSanitizer support" OFF) -<<<<<<< HEAD option(ENABLE_PERFETTO "Enable use of perfetto." OFF) if(ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) - if(ENABLE_PERFETT) + if(ENABLE_PERFETTO) message(FATAL_ERROR "Perfetto and analyzer builds cannot be enabled at the same time") endif() -======= - -if(ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) ->>>>>>> main set(STRIP_DEBUG_DEFAULT OFF) set(ANALYZERS_ENABLED ON) else() @@ -109,19 +104,11 @@ else() set(USES_LIBSTDCPP True) endif() -<<<<<<< HEAD if(ANALYZERS_ENABLED OR ENABLE_PERFETTO) message(STATUS "Analyzers or perfetto enabled") set(SHARED_LIB_NAME xa::shared-no-abi) else() message(STATUS "NO analyzers or perfetto enabled") -======= -if(ANALYZERS_ENABLED) - message(STATUS "Analyzers enabled") - set(SHARED_LIB_NAME xa::shared-no-abi) -else() - message(STATUS "NO analyzers enabled") ->>>>>>> main set(SHARED_LIB_NAME xa::shared) endif() # @@ -184,7 +171,6 @@ macro(xa_add_compile_definitions TARGET) PLATFORM_ANDROID ) -<<<<<<< HEAD if(ENABLE_PERFETTO) target_compile_definitions( ${TARGET} @@ -202,8 +188,6 @@ macro(xa_add_compile_definitions TARGET) ) endif() -======= ->>>>>>> main if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") target_compile_definitions( ${TARGET} @@ -480,14 +464,11 @@ add_link_options("$<$:${COMMON_C_LINKER_ARGS}>") add_subdirectory(libunwind) add_subdirectory(lz4) -<<<<<<< HEAD if(ENABLE_PERFETTO) add_subdirectory(perfetto) endif() -======= ->>>>>>> main add_subdirectory(libstub) add_subdirectory(shared) add_subdirectory(java-interop) diff --git a/src/native/CMakePresets.json.in b/src/native/CMakePresets.json.in index 525cef68548..21982e8cb6c 100644 --- a/src/native/CMakePresets.json.in +++ b/src/native/CMakePresets.json.in @@ -53,11 +53,7 @@ }, { -<<<<<<< HEAD "name": "use-stdlib", -======= - "name": "analyzers-common", ->>>>>>> main "hidden": true, "inherits": "common", "cacheVariables": { @@ -81,21 +77,13 @@ { "name": "analyzers-debug", "hidden": true, -<<<<<<< HEAD "inherits": ["use-stdlib", "common-debug"] -======= - "inherits": ["analyzers-common", "common-debug"] ->>>>>>> main }, { "name": "analyzers-release", "hidden": true, -<<<<<<< HEAD "inherits": ["use-stdlib", "common-release"] -======= - "inherits": ["analyzers-common", "common-release"] ->>>>>>> main }, { @@ -143,7 +131,6 @@ }, { -<<<<<<< HEAD "name": "perfetto-common", "hidden": true, "cacheVariables": { @@ -152,8 +139,6 @@ }, { -======= ->>>>>>> main "name": "asan-common", "hidden": true, "cacheVariables": { @@ -180,7 +165,6 @@ }, { -<<<<<<< HEAD "name": "perfetto-debug-armeabi-v7a", "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-armeabi-v7a"] }, @@ -194,21 +178,12 @@ "name": "analyzers-debug-armeabi-v7a", "hidden": true, "inherits": ["use-stdlib", "common-debug", "common-armeabi-v7a"] -======= - "name": "analyzers-debug-armeabi-v7a", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-armeabi-v7a"] ->>>>>>> main }, { "name": "analyzers-release-armeabi-v7a", "hidden": true, -<<<<<<< HEAD "inherits": ["use-stdlib", "common-release", "common-armeabi-v7a"] -======= - "inherits": ["analyzers-common", "common-release", "common-armeabi-v7a"] ->>>>>>> main }, { @@ -244,7 +219,6 @@ }, { -<<<<<<< HEAD "name": "perfetto-debug-arm64-v8a", "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-arm64-v8a"] }, @@ -258,21 +232,12 @@ "name": "analyzers-debug-arm64-v8a", "hidden": true, "inherits": ["use-stdlib", "common-debug", "common-arm64-v8a"] -======= - "name": "analyzers-debug-arm64-v8a", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-arm64-v8a"] ->>>>>>> main }, { "name": "analyzers-release-arm64-v8a", "hidden": true, -<<<<<<< HEAD "inherits": ["use-stdlib", "common-release", "common-arm64-v8a"] -======= - "inherits": ["analyzers-common", "common-release", "common-arm64-v8a"] ->>>>>>> main }, { @@ -308,7 +273,6 @@ }, { -<<<<<<< HEAD "name": "perfetto-debug-x86", "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-x86"] }, @@ -322,21 +286,12 @@ "name": "analyzers-debug-x86", "hidden": true, "inherits": ["use-stdlib", "common-debug", "common-x86"] -======= - "name": "analyzers-debug-x86", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-x86"] ->>>>>>> main }, { "name": "analyzers-release-x86", "hidden": true, -<<<<<<< HEAD "inherits": ["use-stdlib", "common-release", "common-x86"] -======= - "inherits": ["analyzers-common", "common-release", "common-x86"] ->>>>>>> main }, { @@ -372,7 +327,6 @@ }, { -<<<<<<< HEAD "name": "perfetto-debug-x86_64", "inherits": ["use-stdlib", "perfetto-common", "common-debug", "common-x86_64"] }, @@ -386,21 +340,12 @@ "name": "analyzers-debug-x86_64", "hidden": true, "inherits": ["use-stdlib", "common-debug", "common-x86_64"] -======= - "name": "analyzers-debug-x86_64", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-x86_64"] ->>>>>>> main }, { "name": "analyzers-release-x86_64", "hidden": true, -<<<<<<< HEAD "inherits": ["use-stdlib", "common-release", "common-x86_64"] -======= - "inherits": ["analyzers-common", "common-release", "common-x86_64"] ->>>>>>> main }, { diff --git a/src/native/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 14289ed4393..30f8026437f 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -42,14 +42,9 @@ 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}") -<<<<<<< HEAD set(XAMARIN_MONO_ANDROID_PERFETTO_LIB "mono-android-perfetto.${XAMARIN_MONO_ANDROID_SUFFIX}") list(APPEND XAMARIN_MONODROID_COMMON_SOURCES -======= - -set(XAMARIN_MONODROID_SOURCES ->>>>>>> main debug-constants.cc debug.cc embedded-assemblies-zip.cc @@ -59,10 +54,7 @@ set(XAMARIN_MONODROID_SOURCES mono-log-adapter.cc monodroid-glue.cc monodroid-networkinfo.cc -<<<<<<< HEAD monodroid-profiling.cc -======= ->>>>>>> main monodroid-tracing.cc monovm-properties.cc osbridge.cc @@ -74,17 +66,12 @@ set(XAMARIN_MONODROID_SOURCES xamarin_getifaddrs.cc ) -<<<<<<< HEAD -if(NOT DEBUG_BUILD) - list(APPEND XAMARIN_MONODROID_COMMON_SOURCES -======= list(APPEND LOCAL_CLANG_CHECK_SOURCES - ${XAMARIN_MONODROID_SOURCES} + ${XAMARIN_MONODROID_COMMON_SOURCES} ) if(NOT DEBUG_BUILD) - list(APPEND XAMARIN_MONODROID_SOURCES ->>>>>>> main + list(APPEND XAMARIN_MONODROID_COMMON_SOURCES xamarin-android-app-context.cc ) @@ -92,7 +79,6 @@ if(NOT DEBUG_BUILD) xamarin-android-app-context.cc ) endif() -<<<<<<< HEAD list(APPEND XAMARIN_MONODROID_SOURCES ${XAMARIN_MONODROID_COMMON_SOURCES} @@ -101,9 +87,6 @@ list(APPEND XAMARIN_MONODROID_SOURCES list(APPEND XAMARIN_MONODROID_PERFETTO_SOURCES ${XAMARIN_MONODROID_COMMON_SOURCES} ) -======= -add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") ->>>>>>> main if(NOT USES_LIBSTDCPP) list(APPEND XAMARIN_MONODROID_SOURCES @@ -111,7 +94,6 @@ if(NOT USES_LIBSTDCPP) ) endif() -<<<<<<< HEAD add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") # Build @@ -233,99 +215,3 @@ else() -llog ) 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}) ->>>>>>> main diff --git a/src/native/runtime-base/util.hh b/src/native/runtime-base/util.hh index a1be1a82abe..32f5f7f0a8a 100644 --- a/src/native/runtime-base/util.hh +++ b/src/native/runtime-base/util.hh @@ -33,10 +33,7 @@ static inline constexpr int FALSE = 0; #include #include -<<<<<<< HEAD #include -======= ->>>>>>> main #include #include #include diff --git a/src/native/shared/CMakeLists.txt b/src/native/shared/CMakeLists.txt index 5a3845b34fd..699b1114380 100644 --- a/src/native/shared/CMakeLists.txt +++ b/src/native/shared/CMakeLists.txt @@ -14,7 +14,6 @@ set(XA_SHARED_SOURCES log_functions.cc new_delete.cc ) -<<<<<<< HEAD if(ENABLE_PERFETTO) list(APPEND XA_SHARED_SOURCES @@ -22,8 +21,6 @@ if(ENABLE_PERFETTO) ) endif() -======= ->>>>>>> main add_clang_check_sources("${XA_SHARED_SOURCES};${XA_SHARED_CXX_ABI_SOURCES}") set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") @@ -54,7 +51,6 @@ macro(lib_target_options TARGET_NAME) "$" ) -<<<<<<< HEAD if(ENABLE_PERFETTO) target_link_libraries( ${TARGET_NAME} @@ -63,8 +59,6 @@ macro(lib_target_options TARGET_NAME) ) endif() -======= ->>>>>>> main target_link_libraries( ${TARGET_NAME} PUBLIC From f44cb4a8ec2158d58916b679e5e8a61a6b5c4131 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 3 Jun 2024 18:08:08 +0200 Subject: [PATCH 37/49] Add Perfetto v45.0 SDK sources --- src-ThirdParty/perfetto/perfetto.cc | 64965 ++++++++++ src-ThirdParty/perfetto/perfetto.h | 166356 +++++++++++++++++++++++++ 2 files changed, 231321 insertions(+) create mode 100644 src-ThirdParty/perfetto/perfetto.cc create mode 100644 src-ThirdParty/perfetto/perfetto.h diff --git a/src-ThirdParty/perfetto/perfetto.cc b/src-ThirdParty/perfetto/perfetto.cc new file mode 100644 index 00000000000..2ac9f80755d --- /dev/null +++ b/src-ThirdParty/perfetto/perfetto.cc @@ -0,0 +1,64965 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is automatically generated by gen_amalgamated. Do not edit. + +// gen_amalgamated: predefined macros +#if !defined(PERFETTO_IMPLEMENTATION) +#define PERFETTO_IMPLEMENTATION +#endif +#include "perfetto.h" +// gen_amalgamated begin source: src/base/default_platform.cc +// gen_amalgamated begin header: include/perfetto/ext/base/platform.h +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ +#define INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ + +namespace perfetto { +namespace base { +namespace platform { + +// Executed before entering a syscall (e.g. poll, read, write etc) which might +// block. +// This is overridden in Google internal builds for dealing with userspace +// scheduling. +void BeforeMaybeBlockingSyscall(); + +// Executed after entering a syscall (e.g. poll, read, write etc) which might +// block. +// This is overridden in Google internal builds for dealing with userspace +// scheduling. +void AfterMaybeBlockingSyscall(); + +} // namespace platform +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_PLATFORM_H_ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h" + +namespace perfetto { +namespace base { +namespace platform { + +// This is a no-op outside of Google3 where we have some custom logic to deal +// with the userspace scheduler. +void BeforeMaybeBlockingSyscall() {} + +// This is a no-op outside of Google3 where we have some custom logic to deal +// with the userspace scheduler. +void AfterMaybeBlockingSyscall() {} + +} // namespace platform +} // namespace base +} // namespace perfetto +// gen_amalgamated begin source: src/base/android_utils.cc +// gen_amalgamated begin header: include/perfetto/ext/base/android_utils.h +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ +#define INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ + +#include + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" + +namespace perfetto { +namespace base { + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) + +// Returns the value of the Android system property named `name`. If the +// property does not exist, returns an empty string (a non-existing property is +// the same as a property with an empty value for this API). +std::string GetAndroidProp(const char* name); + +#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/ext/base/android_utils.h" + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" + +#include + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) +#include +#endif + +// gen_amalgamated expanded: #include "perfetto/base/compiler.h" +// gen_amalgamated expanded: #include "perfetto/base/logging.h" + +namespace perfetto { +namespace base { + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) + +std::string GetAndroidProp(const char* name) { + std::string ret; +#if __ANDROID_API__ >= 26 + const prop_info* pi = __system_property_find(name); + if (!pi) { + return ret; + } + __system_property_read_callback( + pi, + [](void* dst_void, const char*, const char* value, uint32_t) { + std::string& dst = *static_cast(dst_void); + dst = value; + }, + &ret); +#else // __ANDROID_API__ < 26 + char value_buf[PROP_VALUE_MAX]; + int len = __system_property_get(name, value_buf); + if (len > 0 && static_cast(len) < sizeof(value_buf)) { + ret = std::string(value_buf, static_cast(len)); + } +#endif + return ret; +} + +#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) + +} // namespace base +} // namespace perfetto +// gen_amalgamated begin source: src/base/base64.cc +// gen_amalgamated begin header: include/perfetto/ext/base/base64.h +// gen_amalgamated begin header: include/perfetto/ext/base/string_view.h +// gen_amalgamated begin header: include/perfetto/ext/base/hash.h +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_HASH_H_ +#define INCLUDE_PERFETTO_EXT_BASE_HASH_H_ + +#include +#include +#include +#include +#include + +namespace perfetto { +namespace base { + +// A helper class which computes a 64-bit hash of the input data. +// The algorithm used is FNV-1a as it is fast and easy to implement and has +// relatively few collisions. +// WARNING: This hash function should not be used for any cryptographic purpose. +class Hasher { + public: + // Creates an empty hash object + Hasher() {} + + // Hashes a numeric value. + template < + typename T, + typename std::enable_if::value, bool>::type = true> + void Update(T data) { + Update(reinterpret_cast(&data), sizeof(data)); + } + + // Using the loop instead of "Update(str, strlen(str))" to avoid looping twice + void Update(const char* str) { + for (const auto* p = str; *p; ++p) + Update(*p); + } + + // Hashes a byte array. + void Update(const char* data, size_t size) { + for (size_t i = 0; i < size; i++) { + result_ ^= static_cast(data[i]); + // Note: Arithmetic overflow of unsigned integers is well defined in C++ + // standard unlike signed integers. + // https://stackoverflow.com/a/41280273 + result_ *= kFnv1a64Prime; + } + } + + // Allow hashing anything that has a |data| field, a |size| field, + // and has the kHashable trait (e.g., base::StringView). + template > + void Update(const T& t) { + Update(t.data(), t.size()); + } + + void Update(const std::string& s) { Update(s.data(), s.size()); } + + uint64_t digest() const { return result_; } + + // Usage: + // uint64_t hashed_value = Hash::Combine(33, false, "ABC", 458L, 3u, 'x'); + template + static uint64_t Combine(Ts&&... args) { + Hasher hasher; + hasher.UpdateAll(std::forward(args)...); + return hasher.digest(); + } + + // `hasher.UpdateAll(33, false, "ABC")` is shorthand for: + // `hasher.Update(33); hasher.Update(false); hasher.Update("ABC");` + void UpdateAll() {} + + template + void UpdateAll(T&& arg, Ts&&... args) { + Update(arg); + UpdateAll(std::forward(args)...); + } + + private: + static constexpr uint64_t kFnv1a64OffsetBasis = 0xcbf29ce484222325; + static constexpr uint64_t kFnv1a64Prime = 0x100000001b3; + + uint64_t result_ = kFnv1a64OffsetBasis; +}; + +// This is for using already-hashed key into std::unordered_map and avoid the +// cost of re-hashing. Example: +// unordered_map my_map. +template +struct AlreadyHashed { + size_t operator()(const T& x) const { return static_cast(x); } +}; + +// base::Hash uses base::Hasher for integer values and falls base to std::hash +// for other types. This is needed as std::hash for integers is just the +// identity function and Perfetto uses open-addressing hash table, which are +// very sensitive to hash quality and are known to degrade in performance +// when using std::hash. +template +struct Hash { + // Version for ints, using base::Hasher. + template + auto operator()(const U& x) -> + typename std::enable_if::value, size_t>::type + const { + Hasher hash; + hash.Update(x); + return static_cast(hash.digest()); + } + + // Version for non-ints, falling back to std::hash. + template + auto operator()(const U& x) -> + typename std::enable_if::value, size_t>::type + const { + return std::hash()(x); + } +}; + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_HASH_H_ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ +#define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ + +#include + +#include +#include + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" +// gen_amalgamated expanded: #include "perfetto/base/logging.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/hash.h" + +namespace perfetto { +namespace base { + +// A string-like object that refers to a non-owned piece of memory. +// Strings are internally NOT null terminated. +class StringView { + public: + // Allow hashing with base::Hash. + static constexpr bool kHashable = true; + static constexpr size_t npos = static_cast(-1); + + StringView() : data_(nullptr), size_(0) {} + StringView(const StringView&) = default; + StringView& operator=(const StringView&) = default; + StringView(const char* data, size_t size) : data_(data), size_(size) { + PERFETTO_DCHECK(size == 0 || data != nullptr); + } + + // Allow implicit conversion from any class that has a |data| and |size| field + // and has the kConvertibleToStringView trait (e.g., protozero::ConstChars). + template > + StringView(const T& x) : StringView(x.data, x.size) { + PERFETTO_DCHECK(x.size == 0 || x.data != nullptr); + } + + // Creates a StringView from a null-terminated C string. + // Deliberately not "explicit". + StringView(const char* cstr) : data_(cstr), size_(strlen(cstr)) { + PERFETTO_DCHECK(cstr != nullptr); + } + + // This instead has to be explicit, as creating a StringView out of a + // std::string can be subtle. + explicit StringView(const std::string& str) + : data_(str.data()), size_(str.size()) {} + + bool empty() const { return size_ == 0; } + size_t size() const { return size_; } + const char* data() const { return data_; } + const char* begin() const { return data_; } + const char* end() const { return data_ + size_; } + + char at(size_t pos) const { + PERFETTO_DCHECK(pos < size_); + return data_[pos]; + } + + size_t find(char c, size_t start_pos = 0) const { + for (size_t i = start_pos; i < size_; ++i) { + if (data_[i] == c) + return i; + } + return npos; + } + + size_t find(const StringView& str, size_t start_pos = 0) const { + if (start_pos > size()) + return npos; + auto it = std::search(begin() + start_pos, end(), str.begin(), str.end()); + size_t pos = static_cast(it - begin()); + return pos + str.size() <= size() ? pos : npos; + } + + size_t find(const char* str, size_t start_pos = 0) const { + return find(StringView(str), start_pos); + } + + size_t rfind(char c) const { + for (size_t i = size_; i > 0; --i) { + if (data_[i - 1] == c) + return i - 1; + } + return npos; + } + + StringView substr(size_t pos, size_t count = npos) const { + if (pos >= size_) + return StringView("", 0); + size_t rcount = std::min(count, size_ - pos); + return StringView(data_ + pos, rcount); + } + + bool CaseInsensitiveEq(const StringView& other) const { + if (size() != other.size()) + return false; + if (size() == 0) + return true; +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + return _strnicmp(data(), other.data(), size()) == 0; +#else + return strncasecmp(data(), other.data(), size()) == 0; +#endif + } + + bool StartsWith(const StringView& other) const { + if (other.size() == 0) + return true; + if (size() == 0) + return false; + if (other.size() > size()) + return false; + return memcmp(data(), other.data(), other.size()) == 0; + } + + bool EndsWith(const StringView& other) const { + if (other.size() == 0) + return true; + if (size() == 0) + return false; + if (other.size() > size()) + return false; + size_t off = size() - other.size(); + return memcmp(data() + off, other.data(), other.size()) == 0; + } + + std::string ToStdString() const { + return size_ == 0 ? "" : std::string(data_, size_); + } + + uint64_t Hash() const { + base::Hasher hasher; + hasher.Update(data_, size_); + return hasher.digest(); + } + + private: + const char* data_ = nullptr; + size_t size_ = 0; +}; + +inline bool operator==(const StringView& x, const StringView& y) { + if (x.size() != y.size()) + return false; + if (x.size() == 0) + return true; + return memcmp(x.data(), y.data(), x.size()) == 0; +} + +inline bool operator!=(const StringView& x, const StringView& y) { + return !(x == y); +} + +inline bool operator<(const StringView& x, const StringView& y) { + auto size = std::min(x.size(), y.size()); + if (size == 0) + return x.size() < y.size(); + int result = memcmp(x.data(), y.data(), size); + return result < 0 || (result == 0 && x.size() < y.size()); +} + +inline bool operator>=(const StringView& x, const StringView& y) { + return !(x < y); +} + +inline bool operator>(const StringView& x, const StringView& y) { + return y < x; +} + +inline bool operator<=(const StringView& x, const StringView& y) { + return !(y < x); +} + +} // namespace base +} // namespace perfetto + +template <> +struct std::hash<::perfetto::base::StringView> { + size_t operator()(const ::perfetto::base::StringView& sv) const { + return static_cast(sv.Hash()); + } +}; + +#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_ +// gen_amalgamated begin header: include/perfetto/ext/base/utils.h +// gen_amalgamated begin header: include/perfetto/ext/base/sys_types.h +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ +#define INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ + +// This headers deals with sys types commonly used in the codebase that are +// missing on Windows. + +#include +#include + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + +#if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC) +// MinGW has these. clang-cl and MSVC, which use just the Windows SDK, don't. +using uid_t = int; +using pid_t = int; +#endif // !GCC + +#if defined(_WIN64) +using ssize_t = int64_t; +#else +using ssize_t = long; +#endif // _WIN64 + +#endif // OS_WIN + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && !defined(AID_SHELL) +// From libcutils' android_filesystem_config.h . +#define AID_SHELL 2000 +#endif + +namespace perfetto { +namespace base { + +// The machine ID used in the tracing core. +using MachineID = uint32_t; +// The default value reserved for the host trace. +constexpr MachineID kDefaultMachineID = 0; + +constexpr uid_t kInvalidUid = static_cast(-1); +constexpr pid_t kInvalidPid = static_cast(-1); + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ +#define INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" +// gen_amalgamated expanded: #include "perfetto/base/compiler.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/sys_types.h" + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +// Even if Windows has errno.h, the all syscall-restart behavior does not apply. +// Trying to handle EINTR can cause more harm than good if errno is left stale. +// Chromium does the same. +#define PERFETTO_EINTR(x) (x) +#else +#define PERFETTO_EINTR(x) \ + ([&] { \ + decltype(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + } while (eintr_wrapper_result == -1 && errno == EINTR); \ + return eintr_wrapper_result; \ + }()) +#endif + +namespace perfetto { +namespace base { + +namespace internal { +extern std::atomic g_cached_page_size; +uint32_t GetSysPageSizeSlowpath(); +} // namespace internal + +// Returns the system's page size. Use this when dealing with mmap, madvise and +// similar mm-related syscalls. +// This function might be called in hot paths. Avoid calling getpagesize() all +// the times, in many implementations getpagesize() calls sysconf() which is +// not cheap. +inline uint32_t GetSysPageSize() { + const uint32_t page_size = + internal::g_cached_page_size.load(std::memory_order_relaxed); + return page_size != 0 ? page_size : internal::GetSysPageSizeSlowpath(); +} + +template +constexpr size_t ArraySize(const T (&)[TSize]) { + return TSize; +} + +// Function object which invokes 'free' on its parameter, which must be +// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr: +// +// std::unique_ptr foo_ptr( +// static_cast(malloc(sizeof(int)))); +struct FreeDeleter { + inline void operator()(void* ptr) const { free(ptr); } +}; + +template +constexpr T AssumeLittleEndian(T value) { +#if !PERFETTO_IS_LITTLE_ENDIAN() + static_assert(false, "Unimplemented on big-endian archs"); +#endif + return value; +} + +// Round up |size| to a multiple of |alignment| (must be a power of two). +inline constexpr size_t AlignUp(size_t size, size_t alignment) { + return (size + alignment - 1) & ~(alignment - 1); +} + +// TODO(primiano): clean this up and move all existing usages to the constexpr +// version above. +template +constexpr size_t AlignUp(size_t size) { + static_assert((alignment & (alignment - 1)) == 0, "alignment must be a pow2"); + return AlignUp(size, alignment); +} + +inline bool IsAgain(int err) { + return err == EAGAIN || err == EWOULDBLOCK; +} + +// setenv(2)-equivalent. Deals with Windows vs Posix discrepancies. +void SetEnv(const std::string& key, const std::string& value); + +// unsetenv(2)-equivalent. Deals with Windows vs Posix discrepancies. +void UnsetEnv(const std::string& key); + +// Calls mallopt(M_PURGE, 0) on Android. Does nothing on other platforms. +// This forces the allocator to release freed memory. This is used to work +// around various Scudo inefficiencies. See b/170217718. +void MaybeReleaseAllocatorMemToOS(); + +// geteuid() on POSIX OSes, returns 0 on Windows (See comment in utils.cc). +uid_t GetCurrentUserId(); + +// Forks the process. +// Parent: prints the PID of the child, calls |parent_cb| and exits from the +// process with its return value. +// Child: redirects stdio onto /dev/null, chdirs into / and returns. +void Daemonize(std::function parent_cb); + +// Returns the path of the current executable, e.g. /foo/bar/exe. +std::string GetCurExecutablePath(); + +// Returns the directory where the current executable lives in, e.g. /foo/bar. +// This is independent of cwd(). +std::string GetCurExecutableDir(); + +// Memory returned by AlignedAlloc() must be freed via AlignedFree() not just +// free. It makes a difference on Windows where _aligned_malloc() and +// _aligned_free() must be paired. +// Prefer using the AlignedAllocTyped() below which takes care of the pairing. +void* AlignedAlloc(size_t alignment, size_t size); +void AlignedFree(void*); + +// A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}. +template +struct AlignedDeleter { + inline void operator()(T* ptr) const { AlignedFree(ptr); } +}; + +// The remove_extent here and below is to allow defining unique_ptr. +// As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes +// always a T*, not a T[]*. +template +using AlignedUniquePtr = + std::unique_ptr::type>>; + +template +AlignedUniquePtr AlignedAllocTyped(size_t n_membs) { + using TU = typename std::remove_extent::type; + return AlignedUniquePtr( + static_cast(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs))); +} + +// A RAII wrapper to invoke a function when leaving a function/scope. +template +class OnScopeExitWrapper { + public: + explicit OnScopeExitWrapper(Func f) : f_(std::move(f)), active_(true) {} + OnScopeExitWrapper(OnScopeExitWrapper&& other) noexcept + : f_(std::move(other.f_)), active_(other.active_) { + other.active_ = false; + } + ~OnScopeExitWrapper() { + if (active_) + f_(); + } + + private: + Func f_; + bool active_; +}; + +template +PERFETTO_WARN_UNUSED_RESULT OnScopeExitWrapper OnScopeExit(Func f) { + return OnScopeExitWrapper(std::move(f)); +} + +// Returns a xxd-style hex dump (hex + ascii chars) of the input data. +std::string HexDump(const void* data, size_t len, size_t bytes_per_line = 16); +inline std::string HexDump(const std::string& data, + size_t bytes_per_line = 16) { + return HexDump(data.data(), data.size(), bytes_per_line); +} + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_UTILS_H_ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ +#define INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ + +#include +#include + +// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" // For ssize_t. + +namespace perfetto { +namespace base { + +// Returns the length of the destination string (included '=' padding). +// Does NOT include the size of the string null terminator. +inline size_t Base64EncSize(size_t src_size) { + return (src_size + 2) / 3 * 4; +} + +// Returns the upper bound on the length of the destination buffer. +// The actual decoded length might be <= the number returned here. +inline size_t Base64DecSize(size_t src_size) { + return (src_size + 3) / 4 * 3; +} + +// Does NOT null-terminate |dst|. +ssize_t Base64Encode(const void* src, + size_t src_size, + char* dst, + size_t dst_size); + +std::string Base64Encode(const void* src, size_t src_size); + +inline std::string Base64Encode(StringView sv) { + return Base64Encode(sv.data(), sv.size()); +} + +// Returns -1 in case of failure. +ssize_t Base64Decode(const char* src, + size_t src_size, + uint8_t* dst, + size_t dst_size); + +std::optional Base64Decode(const char* src, size_t src_size); + +inline std::optional Base64Decode(StringView sv) { + return Base64Decode(sv.data(), sv.size()); +} + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_BASE64_H_ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/ext/base/base64.h" + +namespace perfetto { +namespace base { + +namespace { + +constexpr char kPadding = '='; + +constexpr char kEncTable[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static_assert(sizeof(kEncTable) == (1u << 6) + sizeof('\0'), "Bad table size"); + +// Maps an ASCII character to its 6-bit value. It only contains translations +// from '+' to 'z'. Supports the standard (+/) and URL-safe (-_) alphabets. +constexpr uint8_t kX = 0xff; // Value used for invalid characters +constexpr uint8_t kDecTable[] = { + 62, kX, 62, kX, 63, 52, 53, 54, 55, 56, // 00 - 09 + 57, 58, 59, 60, 61, kX, kX, kX, 0, kX, // 10 - 19 + kX, kX, 0, 1, 2, 3, 4, 5, 6, 7, // 20 - 29 + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, // 30 - 39 + 18, 19, 20, 21, 22, 23, 24, 25, kX, kX, // 40 - 49 + kX, kX, 63, kX, 26, 27, 28, 29, 30, 31, // 50 - 59 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, // 60 - 69 + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 70 - 79 +}; +constexpr char kMinDecChar = '+'; +constexpr char kMaxDecChar = 'z'; +static_assert(kMaxDecChar - kMinDecChar <= sizeof(kDecTable), "Bad table size"); + +inline uint8_t DecodeChar(char c) { + if (c < kMinDecChar || c > kMaxDecChar) + return kX; + return kDecTable[c - kMinDecChar]; +} + +} // namespace + +ssize_t Base64Encode(const void* src, + size_t src_size, + char* dst, + size_t dst_size) { + const size_t padded_dst_size = Base64EncSize(src_size); + if (dst_size < padded_dst_size) + return -1; // Not enough space in output. + + const uint8_t* rd = static_cast(src); + const uint8_t* const end = rd + src_size; + size_t wr_size = 0; + while (rd < end) { + uint8_t s[3]{}; + s[0] = *(rd++); + dst[wr_size++] = kEncTable[s[0] >> 2]; + + uint8_t carry0 = static_cast((s[0] & 0x03) << 4); + if (PERFETTO_LIKELY(rd < end)) { + s[1] = *(rd++); + dst[wr_size++] = kEncTable[carry0 | (s[1] >> 4)]; + } else { + dst[wr_size++] = kEncTable[carry0]; + dst[wr_size++] = kPadding; + dst[wr_size++] = kPadding; + break; + } + + uint8_t carry1 = static_cast((s[1] & 0x0f) << 2); + if (PERFETTO_LIKELY(rd < end)) { + s[2] = *(rd++); + dst[wr_size++] = kEncTable[carry1 | (s[2] >> 6)]; + } else { + dst[wr_size++] = kEncTable[carry1]; + dst[wr_size++] = kPadding; + break; + } + + dst[wr_size++] = kEncTable[s[2] & 0x3f]; + } + PERFETTO_DCHECK(wr_size == padded_dst_size); + return static_cast(padded_dst_size); +} + +std::string Base64Encode(const void* src, size_t src_size) { + std::string dst; + dst.resize(Base64EncSize(src_size)); + auto res = Base64Encode(src, src_size, &dst[0], dst.size()); + PERFETTO_CHECK(res == static_cast(dst.size())); + return dst; +} + +ssize_t Base64Decode(const char* src, + size_t src_size, + uint8_t* dst, + size_t dst_size) { + const size_t min_dst_size = Base64DecSize(src_size); + if (dst_size < min_dst_size) + return -1; + + const char* rd = src; + const char* const end = src + src_size; + size_t wr_size = 0; + + char s[4]{}; + while (rd < end) { + uint8_t d[4]; + for (uint32_t j = 0; j < 4; j++) { + // Padding is only feasible for the last 2 chars of each group of 4. + s[j] = rd < end ? *(rd++) : (j < 2 ? '\0' : kPadding); + d[j] = DecodeChar(s[j]); + if (d[j] == kX) + return -1; // Invalid input char. + } + dst[wr_size] = static_cast((d[0] << 2) | (d[1] >> 4)); + dst[wr_size + 1] = static_cast((d[1] << 4) | (d[2] >> 2)); + dst[wr_size + 2] = static_cast((d[2] << 6) | (d[3])); + wr_size += 3; + } + + PERFETTO_CHECK(wr_size <= dst_size); + wr_size -= (s[3] == kPadding ? 1 : 0) + (s[2] == kPadding ? 1 : 0); + return static_cast(wr_size); +} + +std::optional Base64Decode(const char* src, size_t src_size) { + std::string dst; + dst.resize(Base64DecSize(src_size)); + auto res = Base64Decode(src, src_size, reinterpret_cast(&dst[0]), + dst.size()); + if (res < 0) + return std::nullopt; // Decoding error. + + PERFETTO_CHECK(res <= static_cast(dst.size())); + dst.resize(static_cast(res)); + return std::make_optional(dst); +} + +} // namespace base +} // namespace perfetto +// gen_amalgamated begin source: src/base/crash_keys.cc +// gen_amalgamated begin header: include/perfetto/ext/base/crash_keys.h +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ +#define INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ + +#include +#include + +#include +#include + +// gen_amalgamated expanded: #include "perfetto/base/compiler.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" + +// Crash keys are very simple global variables with static-storage that +// are reported on crash time for managed crashes (CHECK/FATAL/Watchdog). +// - Translation units can define a CrashKey and register it at some point +// during initialization. +// - CrashKey instances must be long-lived. They should really be just global +// static variable in the anonymous namespace. +// Example: +// subsystem_1.cc +// CrashKey g_client_id("ipc_client_id"); +// ... +// OnIpcReceived(client_id) { +// g_client_id.Set(client_id); +// ... // Process the IPC +// g_client_id.Clear(); +// } +// Or equivalently: +// OnIpcReceived(client_id) { +// auto scoped_key = g_client_id.SetScoped(client_id); +// ... // Process the IPC +// } +// +// If a crash happens while processing the IPC, the crash report will +// have a line "ipc_client_id: 42". +// +// Thread safety considerations: +// CrashKeys can be registered and set/cleared from any thread. +// There is no compelling use-case to have full acquire/release consistency when +// setting a key. This means that if a thread crashes immediately after a +// crash key has been set on another thread, the value printed on the crash +// report could be incomplete. The code guarantees defined behavior and does +// not rely on null-terminated string (in the worst case 32 bytes of random +// garbage will be printed out). + +// The tests live in logging_unittest.cc. + +namespace perfetto { +namespace base { + +constexpr size_t kCrashKeyMaxStrSize = 32; + +// CrashKey instances must be long lived +class CrashKey { + public: + class ScopedClear { + public: + explicit ScopedClear(CrashKey* k) : key_(k) {} + ~ScopedClear() { + if (key_) + key_->Clear(); + } + ScopedClear(const ScopedClear&) = delete; + ScopedClear& operator=(const ScopedClear&) = delete; + ScopedClear& operator=(ScopedClear&&) = delete; + ScopedClear(ScopedClear&& other) noexcept : key_(other.key_) { + other.key_ = nullptr; + } + + private: + CrashKey* key_; + }; + + // constexpr so it can be used in the anon namespace without requiring a + // global constructor. + // |name| must be a long-lived string. + constexpr explicit CrashKey(const char* name) + : registered_{}, type_(Type::kUnset), name_(name), str_value_{} {} + CrashKey(const CrashKey&) = delete; + CrashKey& operator=(const CrashKey&) = delete; + CrashKey(CrashKey&&) = delete; + CrashKey& operator=(CrashKey&&) = delete; + + enum class Type : uint8_t { kUnset = 0, kInt, kStr }; + + void Clear() { + int_value_.store(0, std::memory_order_relaxed); + type_.store(Type::kUnset, std::memory_order_relaxed); + } + + void Set(int64_t value) { + int_value_.store(value, std::memory_order_relaxed); + type_.store(Type::kInt, std::memory_order_relaxed); + if (PERFETTO_UNLIKELY(!registered_.load(std::memory_order_relaxed))) + Register(); + } + + void Set(StringView sv) { + size_t len = std::min(sv.size(), sizeof(str_value_) - 1); + for (size_t i = 0; i < len; ++i) + str_value_[i].store(sv.data()[i], std::memory_order_relaxed); + str_value_[len].store('\0', std::memory_order_relaxed); + type_.store(Type::kStr, std::memory_order_relaxed); + if (PERFETTO_UNLIKELY(!registered_.load(std::memory_order_relaxed))) + Register(); + } + + ScopedClear SetScoped(int64_t value) PERFETTO_WARN_UNUSED_RESULT { + Set(value); + return ScopedClear(this); + } + + ScopedClear SetScoped(StringView sv) PERFETTO_WARN_UNUSED_RESULT { + Set(sv); + return ScopedClear(this); + } + + void Register(); + + int64_t int_value() const { + return int_value_.load(std::memory_order_relaxed); + } + size_t ToString(char* dst, size_t len); + + private: + std::atomic registered_; + std::atomic type_; + const char* const name_; + union { + std::atomic str_value_[kCrashKeyMaxStrSize]; + std::atomic int_value_; + }; +}; + +// Fills |dst| with a string containing one line for each crash key +// (excluding the unset ones). +// Returns number of chars written, without counting the NUL terminator. +// This is used in logging.cc when emitting the crash report abort message. +size_t SerializeCrashKeys(char* dst, size_t len); + +void UnregisterAllCrashKeysForTesting(); + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_CRASH_KEYS_H_ +// gen_amalgamated begin header: include/perfetto/ext/base/string_utils.h +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ +#define INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ + +#include +#include +#include + +#include +#include +#include +#include + +// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h" + +namespace perfetto { +namespace base { + +inline char Lowercase(char c) { + return ('A' <= c && c <= 'Z') ? static_cast(c - ('A' - 'a')) : c; +} + +inline char Uppercase(char c) { + return ('a' <= c && c <= 'z') ? static_cast(c + ('A' - 'a')) : c; +} + +inline std::optional CStringToUInt32(const char* s, int base = 10) { + char* endptr = nullptr; + auto value = static_cast(strtoul(s, &endptr, base)); + return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; +} + +inline std::optional CStringToInt32(const char* s, int base = 10) { + char* endptr = nullptr; + auto value = static_cast(strtol(s, &endptr, base)); + return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; +} + +// Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000... +inline std::optional CStringToInt64(const char* s, int base = 10) { + char* endptr = nullptr; + auto value = static_cast(strtoll(s, &endptr, base)); + return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; +} + +inline std::optional CStringToUInt64(const char* s, int base = 10) { + char* endptr = nullptr; + auto value = static_cast(strtoull(s, &endptr, base)); + return (*s && !*endptr) ? std::make_optional(value) : std::nullopt; +} + +double StrToD(const char* nptr, char** endptr); + +inline std::optional CStringToDouble(const char* s) { + char* endptr = nullptr; + double value = StrToD(s, &endptr); + std::optional result(std::nullopt); + if (*s != '\0' && *endptr == '\0') + result = value; + return result; +} + +inline std::optional StringToUInt32(const std::string& s, + int base = 10) { + return CStringToUInt32(s.c_str(), base); +} + +inline std::optional StringToInt32(const std::string& s, + int base = 10) { + return CStringToInt32(s.c_str(), base); +} + +inline std::optional StringToUInt64(const std::string& s, + int base = 10) { + return CStringToUInt64(s.c_str(), base); +} + +inline std::optional StringToInt64(const std::string& s, + int base = 10) { + return CStringToInt64(s.c_str(), base); +} + +inline std::optional StringToDouble(const std::string& s) { + return CStringToDouble(s.c_str()); +} + +bool StartsWith(const std::string& str, const std::string& prefix); +bool EndsWith(const std::string& str, const std::string& suffix); +bool StartsWithAny(const std::string& str, + const std::vector& prefixes); +bool Contains(const std::string& haystack, const std::string& needle); +bool Contains(const std::string& haystack, char needle); +size_t Find(const StringView& needle, const StringView& haystack); +bool CaseInsensitiveEqual(const std::string& first, const std::string& second); +std::string Join(const std::vector& parts, + const std::string& delim); +std::vector SplitString(const std::string& text, + const std::string& delimiter); +std::string StripPrefix(const std::string& str, const std::string& prefix); +std::string StripSuffix(const std::string& str, const std::string& suffix); +std::string TrimWhitespace(const std::string& str); +std::string ToLower(const std::string& str); +std::string ToUpper(const std::string& str); +std::string StripChars(const std::string& str, + const std::string& chars, + char replacement); +std::string ToHex(const char* data, size_t size); +inline std::string ToHex(const std::string& s) { + return ToHex(s.c_str(), s.size()); +} +std::string IntToHexString(uint32_t number); +std::string Uint64ToHexString(uint64_t number); +std::string Uint64ToHexStringNoPrefix(uint64_t number); +std::string ReplaceAll(std::string str, + const std::string& to_replace, + const std::string& replacement); + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +bool WideToUTF8(const std::wstring& source, std::string& output); +bool UTF8ToWide(const std::string& source, std::wstring& output); +#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + +// A BSD-style strlcpy without the return value. +// Copies at most |dst_size|-1 characters. Unlike strncpy, it always \0 +// terminates |dst|, as long as |dst_size| is not 0. +// Unlike strncpy and like strlcpy it does not zero-pad the rest of |dst|. +// Returns nothing. The BSD strlcpy returns the size of |src|, which might +// be > |dst_size|. Anecdotal experience suggests people assume the return value +// is the number of bytes written in |dst|. That assumption can lead to +// dangerous bugs. +// In order to avoid being subtly uncompliant with strlcpy AND avoid misuse, +// the choice here is to return nothing. +inline void StringCopy(char* dst, const char* src, size_t dst_size) { + for (size_t i = 0; i < dst_size; ++i) { + if ((dst[i] = src[i]) == '\0') { + return; // We hit and copied the null terminator. + } + } + + // We were left off at dst_size. We over copied 1 byte. Null terminate. + if (PERFETTO_LIKELY(dst_size > 0)) + dst[dst_size - 1] = 0; +} + +// Like snprintf() but returns the number of chars *actually* written (without +// counting the null terminator) NOT "the number of chars which would have been +// written to the final string if enough space had been available". +// This should be used in almost all cases when the caller uses the return value +// of snprintf(). If the return value is not used, there is no benefit in using +// this wrapper, as this just calls snprintf() and mangles the return value. +// It always null-terminates |dst| (even in case of errors), unless +// |dst_size| == 0. +// Examples: +// SprintfTrunc(x, 4, "123whatever"): returns 3 and writes "123\0". +// SprintfTrunc(x, 4, "123"): returns 3 and writes "123\0". +// SprintfTrunc(x, 3, "123"): returns 2 and writes "12\0". +// SprintfTrunc(x, 2, "123"): returns 1 and writes "1\0". +// SprintfTrunc(x, 1, "123"): returns 0 and writes "\0". +// SprintfTrunc(x, 0, "123"): returns 0 and writes nothing. +// NOTE: This means that the caller has no way to tell when truncation happens +// vs the edge case of *just* fitting in the buffer. +size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...) + PERFETTO_PRINTF_FORMAT(3, 4); + +// Line number starts from 1 +struct LineWithOffset { + base::StringView line; + uint32_t line_offset; + uint32_t line_num; +}; + +// For given string and offset Pfinds a line with character for +// which offset points, what number is this line (starts from 1), and the offset +// inside this line. returns std::nullopt if the offset points to +// line break character or exceeds string length. +std::optional FindLineWithOffset(base::StringView str, + uint32_t offset); + +// A helper class to facilitate construction and usage of write-once stack +// strings. +// Example usage: +// StackString<32> x("format %d %s", 42, string_arg); +// TakeString(x.c_str() | x.string_view() | x.ToStdString()); +// Rather than char x[32] + sprintf. +// Advantages: +// - Avoids useless zero-fills caused by people doing `char buf[32] {}` (mainly +// by fearing unknown snprintf failure modes). +// - Makes the code more robust in case of snprintf truncations (len() and +// string_view() will return the truncated length, unlike snprintf). +template +class StackString { + public: + explicit PERFETTO_PRINTF_FORMAT(/* 1=this */ 2, 3) + StackString(const char* fmt, ...) { + buf_[0] = '\0'; + va_list args; + va_start(args, fmt); + int res = vsnprintf(buf_, sizeof(buf_), fmt, args); + va_end(args); + buf_[sizeof(buf_) - 1] = '\0'; + len_ = res < 0 ? 0 : std::min(static_cast(res), sizeof(buf_) - 1); + } + + StringView string_view() const { return StringView(buf_, len_); } + std::string ToStdString() const { return std::string(buf_, len_); } + const char* c_str() const { return buf_; } + size_t len() const { return len_; } + char* mutable_data() { return buf_; } + + private: + char buf_[N]; + size_t len_ = 0; // Does not include the \0. +}; + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/ext/base/crash_keys.h" + +#include + +#include +#include + +// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h" + +namespace perfetto { +namespace base { + +namespace { + +constexpr size_t kMaxKeys = 32; + +std::atomic g_keys[kMaxKeys]{}; +std::atomic g_num_keys{}; +} // namespace + +void CrashKey::Register() { + // If doesn't matter if we fail below. If there are no slots left, don't + // keep trying re-registering on every Set(), the outcome won't change. + + // If two threads raced on the Register(), avoid registering the key twice. + if (registered_.exchange(true)) + return; + + uint32_t slot = g_num_keys.fetch_add(1); + if (slot >= kMaxKeys) { + PERFETTO_LOG("Too many crash keys registered"); + return; + } + g_keys[slot].store(this); +} + +// Returns the number of chars written, without counting the \0. +size_t CrashKey::ToString(char* dst, size_t len) { + if (len > 0) + *dst = '\0'; + switch (type_.load(std::memory_order_relaxed)) { + case Type::kUnset: + break; + case Type::kInt: + return SprintfTrunc(dst, len, "%s: %" PRId64 "\n", name_, + int_value_.load(std::memory_order_relaxed)); + case Type::kStr: + char buf[sizeof(str_value_)]; + for (size_t i = 0; i < sizeof(str_value_); i++) + buf[i] = str_value_[i].load(std::memory_order_relaxed); + + // Don't assume |str_value_| is properly null-terminated. + return SprintfTrunc(dst, len, "%s: %.*s\n", name_, int(sizeof(buf)), buf); + } + return 0; +} + +void UnregisterAllCrashKeysForTesting() { + g_num_keys.store(0); + for (auto& key : g_keys) + key.store(nullptr); +} + +size_t SerializeCrashKeys(char* dst, size_t len) { + size_t written = 0; + uint32_t num_keys = g_num_keys.load(); + if (len > 0) + *dst = '\0'; + for (uint32_t i = 0; i < num_keys && written < len; i++) { + CrashKey* key = g_keys[i].load(); + if (!key) + continue; // Can happen if we hit this between the add and the store. + written += key->ToString(dst + written, len - written); + } + PERFETTO_DCHECK(written <= len); + PERFETTO_DCHECK(len == 0 || dst[written] == '\0'); + return written; +} + +} // namespace base +} // namespace perfetto +// gen_amalgamated begin source: src/base/ctrl_c_handler.cc +// gen_amalgamated begin header: include/perfetto/ext/base/ctrl_c_handler.h +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ +#define INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ + +namespace perfetto { +namespace base { + +// On Linux/Android/Mac: installs SIGINT + SIGTERM signal handlers. +// On Windows: installs a SetConsoleCtrlHandler() handler. +// The passed handler must be async safe. +using CtrlCHandlerFunction = void (*)(); +void InstallCtrlCHandler(CtrlCHandlerFunction); + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_CTRL_C_HANDLER_H_ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/ext/base/ctrl_c_handler.h" + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" +// gen_amalgamated expanded: #include "perfetto/base/compiler.h" +// gen_amalgamated expanded: #include "perfetto/base/logging.h" + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +#include +#include +#else +#include +#include +#endif + +namespace perfetto { +namespace base { + +namespace { +CtrlCHandlerFunction g_handler = nullptr; +} + +void InstallCtrlCHandler(CtrlCHandlerFunction handler) { + PERFETTO_CHECK(g_handler == nullptr); + g_handler = handler; + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + auto trampoline = [](DWORD type) -> int { + if (type == CTRL_C_EVENT) { + g_handler(); + return true; + } + return false; + }; + ::SetConsoleCtrlHandler(trampoline, true); +#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ + PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ + PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) + // Setup signal handler. + struct sigaction sa {}; + +// Glibc headers for sa_sigaction trigger this. +#pragma GCC diagnostic push +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion" +#endif + sa.sa_handler = [](int) { g_handler(); }; + sa.sa_flags = static_cast(SA_RESETHAND | SA_RESTART); +#pragma GCC diagnostic pop + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); +#else + // Do nothing on NaCL and Fuchsia. + ignore_result(handler); +#endif +} + +} // namespace base +} // namespace perfetto +// gen_amalgamated begin source: src/base/event_fd.cc +// gen_amalgamated begin header: include/perfetto/ext/base/event_fd.h +// gen_amalgamated begin header: include/perfetto/ext/base/scoped_file.h +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ +#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" + +#include + +#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +#include // For DIR* / opendir(). +#endif + +#include + +// gen_amalgamated expanded: #include "perfetto/base/export.h" +// gen_amalgamated expanded: #include "perfetto/base/logging.h" +// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" + +namespace perfetto { +namespace base { + +namespace internal { +// Used for the most common cases of ScopedResource where there is only one +// invalid value. +template +struct DefaultValidityChecker { + static bool IsValid(T t) { return t != InvalidValue; } +}; +} // namespace internal + +// RAII classes for auto-releasing fds and dirs. +// if T is a pointer type, InvalidValue must be nullptr. Doing otherwise +// causes weird unexpected behaviors (See https://godbolt.org/z/5nGMW4). +template > +class ScopedResource { + public: + using ValidityChecker = Checker; + static constexpr T kInvalid = InvalidValue; + + explicit ScopedResource(T t = InvalidValue) : t_(t) {} + ScopedResource(ScopedResource&& other) noexcept { + t_ = other.t_; + other.t_ = InvalidValue; + } + ScopedResource& operator=(ScopedResource&& other) { + reset(other.t_); + other.t_ = InvalidValue; + return *this; + } + T get() const { return t_; } + T operator*() const { return t_; } + explicit operator bool() const { return Checker::IsValid(t_); } + void reset(T r = InvalidValue) { + if (Checker::IsValid(t_)) { + int res = CloseFunction(t_); + if (CheckClose) + PERFETTO_CHECK(res == 0); + } + t_ = r; + } + T release() { + T t = t_; + t_ = InvalidValue; + return t; + } + ~ScopedResource() { reset(InvalidValue); } + + private: + ScopedResource(const ScopedResource&) = delete; + ScopedResource& operator=(const ScopedResource&) = delete; + T t_; +}; + +// Declared in file_utils.h. Forward declared to avoid #include cycles. +int PERFETTO_EXPORT_COMPONENT CloseFile(int fd); + +// Use this for file resources obtained via open() and similar APIs. +using ScopedFile = ScopedResource; +using ScopedFstream = ScopedResource; + +// Use this for resources that are HANDLE on Windows. See comments in +// platform_handle.h +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +using ScopedPlatformHandle = ScopedResource; +#else +// On non-windows systems we alias ScopedPlatformHandle to ScopedFile because +// they are really the same. This is to allow assignments between the two in +// Linux-specific code paths that predate ScopedPlatformHandle. +static_assert(std::is_same::value, ""); +using ScopedPlatformHandle = ScopedFile; + +// DIR* does not exist on Windows. +using ScopedDir = ScopedResource; +#endif + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ +#define INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" +// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" + +namespace perfetto { +namespace base { + +// A waitable event that can be used with poll/select. +// This is really a wrapper around eventfd_create with a pipe-based fallback +// for other platforms where eventfd is not supported. +class EventFd { + public: + EventFd(); + ~EventFd(); + EventFd(EventFd&&) noexcept = default; + EventFd& operator=(EventFd&&) = default; + + // The non-blocking file descriptor that can be polled to wait for the event. + PlatformHandle fd() const { return event_handle_.get(); } + + // Can be called from any thread. + void Notify(); + + // Can be called from any thread. If more Notify() are queued a Clear() call + // can clear all of them (up to 16 per call). + void Clear(); + + private: + // The eventfd, when eventfd is supported, otherwise this is the read end of + // the pipe for fallback mode. + ScopedPlatformHandle event_handle_; + +#if !PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) && \ + !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \ + !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + // On Mac and other non-Linux UNIX platforms a pipe-based fallback is used. + // The write end of the wakeup pipe. + ScopedFile write_fd_; +#endif +}; + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_EVENT_FD_H_ +// gen_amalgamated begin header: include/perfetto/ext/base/pipe.h +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ +#define INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ + +// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" + +namespace perfetto { +namespace base { + +class Pipe { + public: + enum Flags { + kBothBlock = 0, +#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + kBothNonBlock, + kRdNonBlock, + kWrNonBlock, +#endif + }; + + static Pipe Create(Flags = kBothBlock); + + Pipe(); + Pipe(Pipe&&) noexcept; + Pipe& operator=(Pipe&&); + + ScopedPlatformHandle rd; + ScopedPlatformHandle wr; +}; + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_PIPE_H_ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" + +#include +#include + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +#include +#include +#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ + PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) +#include +#include +#else // Mac, Fuchsia and other non-Linux UNIXes +#include +#endif + +// gen_amalgamated expanded: #include "perfetto/base/logging.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" + +namespace perfetto { +namespace base { + +EventFd::~EventFd() = default; + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +EventFd::EventFd() { + event_handle_.reset( + CreateEventA(/*lpEventAttributes=*/nullptr, /*bManualReset=*/true, + /*bInitialState=*/false, /*bInitialState=*/nullptr)); +} + +void EventFd::Notify() { + if (!SetEvent(event_handle_.get())) // 0: fail, !0: success, unlike UNIX. + PERFETTO_DFATAL("EventFd::Notify()"); +} + +void EventFd::Clear() { + if (!ResetEvent(event_handle_.get())) // 0: fail, !0: success, unlike UNIX. + PERFETTO_DFATAL("EventFd::Clear()"); +} + +#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ + PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) + +EventFd::EventFd() { + event_handle_.reset(eventfd(/*initval=*/0, EFD_CLOEXEC | EFD_NONBLOCK)); + PERFETTO_CHECK(event_handle_); +} + +void EventFd::Notify() { + const uint64_t value = 1; + ssize_t ret = write(event_handle_.get(), &value, sizeof(value)); + if (ret <= 0 && errno != EAGAIN) + PERFETTO_DFATAL("EventFd::Notify()"); +} + +void EventFd::Clear() { + uint64_t value; + ssize_t ret = + PERFETTO_EINTR(read(event_handle_.get(), &value, sizeof(value))); + if (ret <= 0 && errno != EAGAIN) + PERFETTO_DFATAL("EventFd::Clear()"); +} + +#else + +EventFd::EventFd() { + // Make the pipe non-blocking so that we never block the waking thread (either + // the main thread or another one) when scheduling a wake-up. + Pipe pipe = Pipe::Create(Pipe::kBothNonBlock); + event_handle_ = ScopedPlatformHandle(std::move(pipe.rd).release()); + write_fd_ = std::move(pipe.wr); +} + +void EventFd::Notify() { + const uint64_t value = 1; + ssize_t ret = write(write_fd_.get(), &value, sizeof(uint8_t)); + if (ret <= 0 && errno != EAGAIN) + PERFETTO_DFATAL("EventFd::Notify()"); +} + +void EventFd::Clear() { + // Drain the byte(s) written to the wake-up pipe. We can potentially read + // more than one byte if several wake-ups have been scheduled. + char buffer[16]; + ssize_t ret = + PERFETTO_EINTR(read(event_handle_.get(), &buffer[0], sizeof(buffer))); + if (ret <= 0 && errno != EAGAIN) + PERFETTO_DFATAL("EventFd::Clear()"); +} +#endif + +} // namespace base +} // namespace perfetto +// gen_amalgamated begin source: src/base/file_utils.cc +// gen_amalgamated begin header: include/perfetto/ext/base/file_utils.h +// gen_amalgamated begin header: include/perfetto/base/status.h +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_BASE_STATUS_H_ +#define INCLUDE_PERFETTO_BASE_STATUS_H_ + +#include +#include +#include +#include + +// gen_amalgamated expanded: #include "perfetto/base/compiler.h" +// gen_amalgamated expanded: #include "perfetto/base/export.h" +// gen_amalgamated expanded: #include "perfetto/base/logging.h" + +namespace perfetto { +namespace base { + +// Represents either the success or the failure message of a function. +// This can used as the return type of functions which would usually return an +// bool for success or int for errno but also wants to add some string context +// (ususally for logging). +// +// Similar to absl::Status, an optional "payload" can also be included with more +// context about the error. This allows passing additional metadata about the +// error (e.g. location of errors, potential mitigations etc). +class PERFETTO_EXPORT_COMPONENT Status { + public: + Status() : ok_(true) {} + explicit Status(std::string msg) : ok_(false), message_(std::move(msg)) { + PERFETTO_CHECK(!message_.empty()); + } + + // Copy operations. + Status(const Status&) = default; + Status& operator=(const Status&) = default; + + // Move operations. The moved-from state is valid but unspecified. + Status(Status&&) noexcept = default; + Status& operator=(Status&&) = default; + + bool ok() const { return ok_; } + + // When ok() is false this returns the error message. Returns the empty string + // otherwise. + const std::string& message() const { return message_; } + const char* c_message() const { return message_.c_str(); } + + ////////////////////////////////////////////////////////////////////////////// + // Payload Management APIs + ////////////////////////////////////////////////////////////////////////////// + + // Payloads can be attached to error statuses to provide additional context. + // + // Payloads are (key, value) pairs, where the key is a string acting as a + // unique "type URL" and the value is an opaque string. The "type URL" should + // be unique, follow the format of a URL and, ideally, documentation on how to + // interpret its associated data should be available. + // + // To attach a payload to a status object, call `Status::SetPayload()`. + // Similarly, to extract the payload from a status, call + // `Status::GetPayload()`. + // + // Note: the payload APIs are only meaningful to call when the status is an + // error. Otherwise, all methods are noops. + + // Gets the payload for the given |type_url| if one exists. + // + // Will always return std::nullopt if |ok()|. + std::optional GetPayload(std::string_view type_url) const; + + // Sets the payload for the given key. The key should + // + // Will always do nothing if |ok()|. + void SetPayload(std::string_view type_url, std::string value); + + // Erases the payload for the given string and returns true if the payload + // existed and was erased. + // + // Will always do nothing if |ok()|. + bool ErasePayload(std::string_view type_url); + + private: + struct Payload { + std::string type_url; + std::string payload; + }; + + bool ok_ = false; + std::string message_; + std::vector payloads_; +}; + +// Returns a status object which represents the Ok status. +inline Status OkStatus() { + return Status(); +} + +PERFETTO_PRINTF_FORMAT(1, 2) Status ErrStatus(const char* format, ...); + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_BASE_STATUS_H_ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ +#define INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ + +#include // For mode_t & O_RDONLY/RDWR. Exists also on Windows. +#include + +#include +#include +#include + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" +// gen_amalgamated expanded: #include "perfetto/base/export.h" +// gen_amalgamated expanded: #include "perfetto/base/status.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" + +namespace perfetto { +namespace base { + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +using FileOpenMode = int; +inline constexpr char kDevNull[] = "NUL"; +#else +using FileOpenMode = mode_t; +inline constexpr char kDevNull[] = "/dev/null"; +#endif + +constexpr FileOpenMode kFileModeInvalid = static_cast(-1); + +bool ReadPlatformHandle(PlatformHandle, std::string* out); +bool ReadFileDescriptor(int fd, std::string* out); +bool ReadFileStream(FILE* f, std::string* out); +bool ReadFile(const std::string& path, std::string* out); + +// A wrapper around read(2). It deals with Linux vs Windows includes. It also +// deals with handling EINTR. Has the same semantics of UNIX's read(2). +ssize_t Read(int fd, void* dst, size_t dst_size); + +// Call write until all data is written or an error is detected. +// +// man 2 write: +// If a write() is interrupted by a signal handler before any bytes are +// written, then the call fails with the error EINTR; if it is +// interrupted after at least one byte has been written, the call +// succeeds, and returns the number of bytes written. +ssize_t WriteAll(int fd, const void* buf, size_t count); + +ssize_t WriteAllHandle(PlatformHandle, const void* buf, size_t count); + +ScopedFile OpenFile(const std::string& path, + int flags, + FileOpenMode = kFileModeInvalid); +ScopedFstream OpenFstream(const char* path, const char* mode); + +// This is an alias for close(). It's to avoid leaking Windows.h in headers. +// Exported because ScopedFile is used in the /include/ext API by Chromium +// component builds. +int PERFETTO_EXPORT_COMPONENT CloseFile(int fd); + +bool FlushFile(int fd); + +// Returns true if mkdir succeeds, false if it fails (see errno in that case). +bool Mkdir(const std::string& path); + +// Calls rmdir() on UNIX, _rmdir() on Windows. +bool Rmdir(const std::string& path); + +// Wrapper around access(path, F_OK). +bool FileExists(const std::string& path); + +// Gets the extension for a filename. If the file has two extensions, returns +// only the last one (foo.pb.gz => .gz). Returns empty string if there is no +// extension. +std::string GetFileExtension(const std::string& filename); + +// Puts the path to all files under |dir_path| in |output|, recursively walking +// subdirectories. File paths are relative to |dir_path|. Only files are +// included, not directories. Path separator is always '/', even on windows (not +// '\'). +base::Status ListFilesRecursive(const std::string& dir_path, + std::vector& output); + +// Sets |path|'s owner group to |group_name| and permission mode bits to +// |mode_bits|. +base::Status SetFilePermissions(const std::string& path, + const std::string& group_name, + const std::string& mode_bits); + +// Returns the size of the file located at |path|, or nullopt in case of error. +std::optional GetFileSize(const std::string& path); + +// Returns the size of the open file |fd|, or nullopt in case of error. +std::optional GetFileSize(PlatformHandle fd); + +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h" + +#include +#include + +#include +#include +#include +#include +#include + +// gen_amalgamated expanded: #include "perfetto/base/build_config.h" +// gen_amalgamated expanded: #include "perfetto/base/compiler.h" +// gen_amalgamated expanded: #include "perfetto/base/logging.h" +// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h" +// gen_amalgamated expanded: #include "perfetto/base/status.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h" +// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +#include +#include +#include +#include +#else +#include +#include +#endif + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ + PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ + PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) +#define PERFETTO_SET_FILE_PERMISSIONS +#include +#include +#include +#include +#include +#endif + +namespace perfetto { +namespace base { +namespace { +constexpr size_t kBufSize = 2048; + +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) +// Wrap FindClose to: (1) make the return unix-style; (2) deal with stdcall. +int CloseFindHandle(HANDLE h) { + return FindClose(h) ? 0 : -1; +} + +std::optional ToUtf16(const std::string str) { + int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), + static_cast(str.size()), nullptr, 0); + if (len < 0) { + return std::nullopt; + } + std::vector tmp; + tmp.resize(static_cast::size_type>(len)); + len = + MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), + tmp.data(), static_cast(tmp.size())); + if (len < 0) { + return std::nullopt; + } + PERFETTO_CHECK(static_cast::size_type>(len) == + tmp.size()); + return std::wstring(tmp.data(), tmp.size()); +} + +#endif + +} // namespace + +ssize_t Read(int fd, void* dst, size_t dst_size) { + ssize_t ret; + platform::BeforeMaybeBlockingSyscall(); +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + ret = _read(fd, dst, static_cast(dst_size)); +#else + ret = PERFETTO_EINTR(read(fd, dst, dst_size)); +#endif + platform::AfterMaybeBlockingSyscall(); + return ret; +} + +bool ReadFileDescriptor(int fd, std::string* out) { + // Do not override existing data in string. + size_t i = out->size(); + + struct stat buf {}; + if (fstat(fd, &buf) != -1) { + if (buf.st_size > 0) + out->resize(i + static_cast(buf.st_size)); + } + + ssize_t bytes_read; + for (;;) { + if (out->size() < i + kBufSize) + out->resize(out->size() + kBufSize); + + bytes_read = Read(fd, &((*out)[i]), kBufSize); + if (bytes_read > 0) { + i += static_cast(bytes_read); + } else { + out->resize(i); + return bytes_read == 0; + } + } +} + +bool ReadPlatformHandle(PlatformHandle h, std::string* out) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + // Do not override existing data in string. + size_t i = out->size(); + + for (;;) { + if (out->size() < i + kBufSize) + out->resize(out->size() + kBufSize); + DWORD bytes_read = 0; + auto res = ::ReadFile(h, &((*out)[i]), kBufSize, &bytes_read, nullptr); + if (res && bytes_read > 0) { + i += static_cast(bytes_read); + } else { + out->resize(i); + const bool is_eof = res && bytes_read == 0; + auto err = res ? 0 : GetLastError(); + // The "Broken pipe" error on Windows is slighly different than Unix: + // On Unix: a "broken pipe" error can happen only on the writer side. On + // the reader there is no broken pipe, just a EOF. + // On windows: the reader also sees a broken pipe error. + // Here we normalize on the Unix behavior, treating broken pipe as EOF. + return is_eof || err == ERROR_BROKEN_PIPE; + } + } +#else + return ReadFileDescriptor(h, out); +#endif +} + +bool ReadFileStream(FILE* f, std::string* out) { + return ReadFileDescriptor(fileno(f), out); +} + +bool ReadFile(const std::string& path, std::string* out) { + base::ScopedFile fd = base::OpenFile(path, O_RDONLY); + if (!fd) + return false; + + return ReadFileDescriptor(*fd, out); +} + +ssize_t WriteAll(int fd, const void* buf, size_t count) { + size_t written = 0; + while (written < count) { + // write() on windows takes an unsigned int size. + uint32_t bytes_left = static_cast( + std::min(count - written, static_cast(UINT32_MAX))); + platform::BeforeMaybeBlockingSyscall(); + ssize_t wr = PERFETTO_EINTR( + write(fd, static_cast(buf) + written, bytes_left)); + platform::AfterMaybeBlockingSyscall(); + if (wr == 0) + break; + if (wr < 0) + return wr; + written += static_cast(wr); + } + return static_cast(written); +} + +ssize_t WriteAllHandle(PlatformHandle h, const void* buf, size_t count) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + DWORD wsize = 0; + if (::WriteFile(h, buf, static_cast(count), &wsize, nullptr)) { + return wsize; + } else { + return -1; + } +#else + return WriteAll(h, buf, count); +#endif +} + +bool FlushFile(int fd) { + PERFETTO_DCHECK(fd != 0); +#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ + PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) + return !PERFETTO_EINTR(fdatasync(fd)); +#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + return !PERFETTO_EINTR(_commit(fd)); +#else + return !PERFETTO_EINTR(fsync(fd)); +#endif +} + +bool Mkdir(const std::string& path) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + return _mkdir(path.c_str()) == 0; +#else + return mkdir(path.c_str(), 0755) == 0; +#endif +} + +bool Rmdir(const std::string& path) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + return _rmdir(path.c_str()) == 0; +#else + return rmdir(path.c_str()) == 0; +#endif +} + +int CloseFile(int fd) { + return close(fd); +} + +ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) { + // If a new file might be created, ensure that the permissions for the new + // file are explicitly specified. + PERFETTO_CHECK((flags & O_CREAT) == 0 || mode != kFileModeInvalid); +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + // Always use O_BINARY on Windows, to avoid silly EOL translations. + ScopedFile fd(_open(path.c_str(), flags | O_BINARY, mode)); +#else + // Always open a ScopedFile with O_CLOEXEC so we can safely fork and exec. + ScopedFile fd(open(path.c_str(), flags | O_CLOEXEC, mode)); +#endif + return fd; +} + +ScopedFstream OpenFstream(const char* path, const char* mode) { + ScopedFstream file; +// On Windows fopen interprets filename using the ANSI or OEM codepage but +// sqlite3_value_text returns a UTF-8 string. To make sure we interpret the +// filename correctly we use _wfopen and a UTF-16 string on windows. +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + auto w_path = ToUtf16(path); + auto w_mode = ToUtf16(mode); + if (w_path && w_mode) { + file.reset(_wfopen(w_path->c_str(), w_mode->c_str())); + } +#else + file.reset(fopen(path, mode)); +#endif + return file; +} + +bool FileExists(const std::string& path) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + return _access(path.c_str(), 0) == 0; +#else + return access(path.c_str(), F_OK) == 0; +#endif +} + +// Declared in base/platform_handle.h. +int ClosePlatformHandle(PlatformHandle handle) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + // Make the return value UNIX-style. + return CloseHandle(handle) ? 0 : -1; +#else + return close(handle); +#endif +} + +base::Status ListFilesRecursive(const std::string& dir_path, + std::vector& output) { + std::string root_dir_path = dir_path; + if (root_dir_path.back() == '\\') { + root_dir_path.back() = '/'; + } else if (root_dir_path.back() != '/') { + root_dir_path.push_back('/'); + } + + // dir_queue contains full paths to the directories. The paths include the + // root_dir_path at the beginning and the trailing slash at the end. + std::deque dir_queue; + dir_queue.push_back(root_dir_path); + + while (!dir_queue.empty()) { + const std::string cur_dir = std::move(dir_queue.front()); + dir_queue.pop_front(); +#if PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) + return base::ErrStatus("ListFilesRecursive not supported yet"); +#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + std::string glob_path = cur_dir + "*"; + // + 1 because we also have to count the NULL terminator. + if (glob_path.length() + 1 > MAX_PATH) + return base::ErrStatus("Directory path %s is too long", dir_path.c_str()); + WIN32_FIND_DATAA ffd; + + base::ScopedResource + hFind(FindFirstFileA(glob_path.c_str(), &ffd)); + if (!hFind) { + // For empty directories, there should be at least one entry '.'. + // If FindFirstFileA returns INVALID_HANDLE_VALUE, this means directory + // couldn't be accessed. + return base::ErrStatus("Failed to open directory %s", cur_dir.c_str()); + } + do { + if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) + continue; + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + std::string subdir_path = cur_dir + ffd.cFileName + '/'; + dir_queue.push_back(subdir_path); + } else { + const std::string full_path = cur_dir + ffd.cFileName; + PERFETTO_CHECK(full_path.length() > root_dir_path.length()); + output.push_back(full_path.substr(root_dir_path.length())); + } + } while (FindNextFileA(*hFind, &ffd)); +#else + ScopedDir dir = ScopedDir(opendir(cur_dir.c_str())); + if (!dir) { + return base::ErrStatus("Failed to open directory %s", cur_dir.c_str()); + } + for (auto* dirent = readdir(dir.get()); dirent != nullptr; + dirent = readdir(dir.get())) { + if (strcmp(dirent->d_name, ".") == 0 || + strcmp(dirent->d_name, "..") == 0) { + continue; + } + if (dirent->d_type == DT_DIR) { + dir_queue.push_back(cur_dir + dirent->d_name + '/'); + } else if (dirent->d_type == DT_REG) { + const std::string full_path = cur_dir + dirent->d_name; + PERFETTO_CHECK(full_path.length() > root_dir_path.length()); + output.push_back(full_path.substr(root_dir_path.length())); + } + } +#endif + } + return base::OkStatus(); +} + +std::string GetFileExtension(const std::string& filename) { + auto ext_idx = filename.rfind('.'); + if (ext_idx == std::string::npos) + return std::string(); + return filename.substr(ext_idx); +} + +base::Status SetFilePermissions(const std::string& file_path, + const std::string& group_name_or_id, + const std::string& mode_bits) { +#ifdef PERFETTO_SET_FILE_PERMISSIONS + PERFETTO_CHECK(!file_path.empty()); + PERFETTO_CHECK(!group_name_or_id.empty()); + + // Default |group_id| to -1 for not changing the group ownership. + gid_t group_id = static_cast(-1); + auto maybe_group_id = base::StringToUInt32(group_name_or_id); + if (maybe_group_id) { // A numerical group ID. + group_id = *maybe_group_id; + } else { // A group name. + struct group* file_group = nullptr; + // Query the group ID of |group|. + do { + file_group = getgrnam(group_name_or_id.c_str()); + } while (file_group == nullptr && errno == EINTR); + if (file_group == nullptr) { + return base::ErrStatus("Failed to get group information of %s ", + group_name_or_id.c_str()); + } + group_id = file_group->gr_gid; + } + + if (PERFETTO_EINTR(chown(file_path.c_str(), geteuid(), group_id))) { + return base::ErrStatus("Failed to chown %s ", file_path.c_str()); + } + + // |mode| accepts values like "0660" as "rw-rw----" mode bits. + auto mode_value = base::StringToInt32(mode_bits, 8); + if (!(mode_bits.size() == 4 && mode_value.has_value())) { + return base::ErrStatus( + "The chmod mode bits must be a 4-digit octal number, e.g. 0660"); + } + if (PERFETTO_EINTR( + chmod(file_path.c_str(), static_cast(mode_value.value())))) { + return base::ErrStatus("Failed to chmod %s", file_path.c_str()); + } + return base::OkStatus(); +#else + base::ignore_result(file_path); + base::ignore_result(group_name_or_id); + base::ignore_result(mode_bits); + return base::ErrStatus( + "Setting file permissions is not supported on this platform"); +#endif +} + +std::optional GetFileSize(const std::string& file_path) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + // This does not use base::OpenFile to avoid getting an exclusive lock. + base::ScopedPlatformHandle fd( + CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); +#else + base::ScopedFile fd(base::OpenFile(file_path, O_RDONLY | O_CLOEXEC)); +#endif + if (!fd) { + return std::nullopt; + } + return GetFileSize(*fd); +} + +std::optional GetFileSize(PlatformHandle fd) { +#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) + LARGE_INTEGER file_size; + file_size.QuadPart = 0; + if (!GetFileSizeEx(fd, &file_size)) { + return std::nullopt; + } + static_assert(sizeof(decltype(file_size.QuadPart)) <= sizeof(uint64_t)); + return static_cast(file_size.QuadPart); +#else + struct stat buf {}; + if (fstat(fd, &buf) == -1) { + return std::nullopt; + } + static_assert(sizeof(decltype(buf.st_size)) <= sizeof(uint64_t)); + return static_cast(buf.st_size); +#endif +} + +} // namespace base +} // namespace perfetto +// gen_amalgamated begin source: src/base/getopt_compat.cc +// gen_amalgamated begin header: include/perfetto/ext/base/getopt_compat.h +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ +#define INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ + +#include // For std::nullptr_t + +// No translation units other than base/getopt.h and getopt_compat_unittest.cc +// should directly include this file. Use base/getopt.h instead. + +namespace perfetto { +namespace base { +namespace getopt_compat { + +// A tiny getopt() replacement for Windows, which doesn't have . +// This implementation is based on the subset of features that we use in the +// Perfetto codebase. It doesn't even try to deal with the full surface of GNU's +// getopt(). +// Limitations: +// - getopt_long_only() is not supported. +// - optional_argument is not supported. That is extremely subtle and caused us +// problems in the past with GNU's getopt. +// - It does not reorder non-option arguments. It behaves like MacOS getopt, or +// GNU's when POSIXLY_CORRECT=1. +// - Doesn't expose optopt or opterr. +// - option.flag and longindex are not supported and must be nullptr. + +enum { + no_argument = 0, + required_argument = 1, +}; + +struct option { + const char* name; + int has_arg; + std::nullptr_t flag; // Only nullptr is supported. + int val; +}; + +extern char* optarg; +extern int optind; +extern int optopt; +extern int opterr; + +int getopt_long(int argc, + char** argv, + const char* shortopts, + const option* longopts, + std::nullptr_t /*longindex is not supported*/); + +int getopt(int argc, char** argv, const char* shortopts); + +} // namespace getopt_compat +} // namespace base +} // namespace perfetto + +#endif // INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// gen_amalgamated expanded: #include "perfetto/ext/base/getopt_compat.h" + +#include +#include +#include + +#include + +// gen_amalgamated expanded: #include "perfetto/base/logging.h" + +namespace perfetto { +namespace base { +namespace getopt_compat { + +char* optarg = nullptr; +int optind = 0; +int optopt = 0; +int opterr = 1; + +namespace { + +char* nextchar = nullptr; + +const option* LookupLongOpt(const std::vector