From 1cf9e25feb2cdfe68005663fc274c4945add2b03 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 11:04:09 +0100 Subject: [PATCH 001/143] Enable static linking with libc++ * Add a version script which hides all the symbols except for the handful we have to export. * Enable exceptions --- src/native/CMakeLists.txt | 2 +- src/native/libmono-android.map.txt | 15 +++++++++++++++ src/native/mono/monodroid/CMakeLists.txt | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/native/libmono-android.map.txt diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index a1cee1367a6..2c52d0e3c56 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -134,7 +134,7 @@ else() set(USES_LIBSTDCPP True) endif() -set(SHARED_LIB_NAME xa::shared) +set(SHARED_LIB_NAME xa::shared-no-abi) # # Needed modules diff --git a/src/native/libmono-android.map.txt b/src/native/libmono-android.map.txt new file mode 100644 index 00000000000..18bcab675ef --- /dev/null +++ b/src/native/libmono-android.map.txt @@ -0,0 +1,15 @@ +LIBMONO_ANDROID { + global: + JNI_OnLoad; + Java_mono_android_Runtime_dumpTimingData; + Java_mono_android_Runtime_init; + Java_mono_android_Runtime_initInternal; + Java_mono_android_Runtime_notifyTimeZoneChanged; + Java_mono_android_Runtime_propagateUncaughtException; + Java_mono_android_Runtime_register; + _monodroid_freeifaddrs; + _monodroid_getifaddrs; + + local: + *; +}; diff --git a/src/native/mono/monodroid/CMakeLists.txt b/src/native/mono/monodroid/CMakeLists.txt index 00c05f97d18..e8026d8306e 100644 --- a/src/native/mono/monodroid/CMakeLists.txt +++ b/src/native/mono/monodroid/CMakeLists.txt @@ -241,7 +241,7 @@ xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) target_link_options(${XAMARIN_MONO_ANDROID_LIB} PRIVATE - -Wl,--version-script,${CMAKE_SOURCE_DIR}/mono/libmono-android.map.txt + -Wl,--version-script,${CMAKE_SOURCE_DIR}/libmono-android.map.txt -Wl,--no-undefined-version ) From dae8f4d870ed9a510ad79d2ef4c1506a8721302e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 11:11:57 +0100 Subject: [PATCH 002/143] Remove C++ ABI compatibility sources --- src/native/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 2c52d0e3c56..a1cee1367a6 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -134,7 +134,7 @@ else() set(USES_LIBSTDCPP True) endif() -set(SHARED_LIB_NAME xa::shared-no-abi) +set(SHARED_LIB_NAME xa::shared) # # Needed modules From b27665fd95e3d81bf17f030bd1498c98b0a0f499 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 16:05:55 +0100 Subject: [PATCH 003/143] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 28 +++--- .../BuildReleaseArm64XFormsDotNet.apkdesc | 99 ++++++++++--------- 2 files changed, 65 insertions(+), 62 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 0d09c5250f4..574f95f396e 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 @@ -5,34 +5,34 @@ "Size": 3036 }, "classes.dex": { - "Size": 22484 + "Size": 389632 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 18288 + "Size": 18296 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 86688 + "Size": 86352 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 117712 + "Size": 116768 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22384 + "Size": 22416 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24392 + "Size": 24376 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { "Size": 25336 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 628216 + "Size": 634384 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20056 + "Size": 20040 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21480 + "Size": 21584 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 20024 @@ -44,10 +44,10 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1524752 + "Size": 903032 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3101112 + "Size": 3196512 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71976 @@ -62,10 +62,10 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 19536 + "Size": 13016 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { "Size": 3266 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 3078677 + "PackageSize": 2984469 } \ 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 ab4f60772ce..3811dba9c93 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 @@ -5,7 +5,10 @@ "Size": 6652 }, "classes.dex": { - "Size": 9172540 + "Size": 9448880 + }, + "classes2.dex": { + "Size": 154180 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -32,25 +35,25 @@ "Size": 19544 }, "lib/arm64-v8a/lib_FormsViewGroup.dll.so": { - "Size": 25424 + "Size": 25184 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 94792 + "Size": 94736 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 535520 + "Size": 522832 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22432 + "Size": 22416 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21448 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23096 + "Size": 23072 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 29896 + "Size": 29792 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { "Size": 36304 @@ -59,7 +62,7 @@ "Size": 25776 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23856 + "Size": 23840 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { "Size": 19608 @@ -71,31 +74,31 @@ "Size": 42480 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24440 + "Size": 24416 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19464 + "Size": 19448 }, "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { "Size": 28456 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 24704 + "Size": 24688 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19864 + "Size": 19848 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19448 + "Size": 19424 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30056 + "Size": 30040 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 50312 + "Size": 49928 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29496 + "Size": 29472 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { "Size": 33808 @@ -107,7 +110,7 @@ "Size": 38784 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 185880 + "Size": 185800 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { "Size": 90320 @@ -116,85 +119,85 @@ "Size": 41152 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21568 + "Size": 21544 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27096 + "Size": 27064 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 958672 + "Size": 956552 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 216680 + "Size": 216720 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { "Size": 62784 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 236920 + "Size": 237120 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 35600 + "Size": 35584 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { "Size": 20216 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21480 + "Size": 21584 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { - "Size": 54168 + "Size": 54408 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 19368 + "Size": 19352 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 20344 + "Size": 20328 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 21472 + "Size": 21448 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { "Size": 81248 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 186352 + "Size": 183584 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19272 + "Size": 19248 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19280 + "Size": 19264 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 22096 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { - "Size": 34960 + "Size": 34760 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.AppCompatResources.dll.so": { - "Size": 24512 + "Size": 24296 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.dll.so": { - "Size": 163240 + "Size": 163072 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CardView.dll.so": { "Size": 24560 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CoordinatorLayout.dll.so": { - "Size": 35912 + "Size": 35680 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Core.dll.so": { - "Size": 151408 + "Size": 151216 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CursorAdapter.dll.so": { "Size": 27168 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.DrawerLayout.dll.so": { - "Size": 33944 + "Size": 33760 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Fragment.dll.so": { - "Size": 72528 + "Size": 72224 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Legacy.Support.Core.UI.dll.so": { "Size": 23896 @@ -212,16 +215,16 @@ "Size": 31592 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.RecyclerView.dll.so": { - "Size": 112248 + "Size": 111896 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SavedState.dll.so": { "Size": 23144 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SwipeRefreshLayout.dll.so": { - "Size": 31952 + "Size": 31672 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager.dll.so": { - "Size": 38048 + "Size": 37752 }, "lib/arm64-v8a/lib_Xamarin.Forms.Core.dll.so": { "Size": 581000 @@ -236,7 +239,7 @@ "Size": 80632 }, "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { - "Size": 84768 + "Size": 84400 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 18832 @@ -245,10 +248,10 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1524624 + "Size": 903032 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3101160 + "Size": 3196512 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71976 @@ -263,7 +266,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 349384 + "Size": 120016 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -419,7 +422,7 @@ "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 98577 + "Size": 98661 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -446,7 +449,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98450 + "Size": 98534 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2486,5 +2489,5 @@ "Size": 812848 } }, - "PackageSize": 10923275 + "PackageSize": 10796357 } \ No newline at end of file From baa83788464d163107c3017b8e012579abd0c138 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 31 Oct 2024 19:19:59 +0100 Subject: [PATCH 004/143] Playing around with some ideas --- .../mono/monodroid/embedded-assemblies.hh | 6 +- src/native/mono/monodroid/monodroid-glue.cc | 7 +- src/native/mono/monodroid/osbridge.cc | 6 +- src/native/mono/shared/cpp-util.hh | 96 ++++--------------- 4 files changed, 26 insertions(+), 89 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index f3447a69840..d78fa6755e1 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -26,7 +26,7 @@ #include #include "cppcompat.hh" #include "shared-constants.hh" -#include +#include "xxhash.hh" #include "util.hh" #include @@ -173,8 +173,8 @@ namespace xamarin::android::internal { abort_unless ( runtime_config_data_size < std::numeric_limits::max (), [] { - return detail::_format_message ("Runtime config binary blob size exceeds %u bytes", - std::numeric_limits::max ()); + return Util::monodroid_strdup_printf ("Runtime config binary blob size exceeds %u bytes", + std::numeric_limits::max ()); } ); size = static_cast(runtime_config_data_size); diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 26547c8e476..a5de62b9030 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -917,10 +917,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( registerType != nullptr, [&error] { - return detail::_format_message ( - "INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", - mono_error_get_message (&error) - ); + return Util::monodroid_strdup_printf("INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", mono_error_get_message (&error)); } ); @@ -949,7 +946,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( initialize != nullptr, [&error] { - return detail::_format_message ( + return Util::monodroid_strdup_printf ( "Failed to obtain unmanaged-callers-only pointer to the Android.Runtime.JNIEnvInit.Initialize method. %s", mono_error_get_message (&error) ); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 919506d3fda..c189efd5754 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -880,7 +880,9 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (j > 0) { abort_unless ( sccs [i]->is_alive, - [&i] { return detail::_format_message ("Bridge SCC at index %d must be alive", i); } + [&i] { + return Util::monodroid_strdup_printf ("Bridge SCC at index %d must be alive", i); + } ); } sccs [i]->is_alive = 1; @@ -908,7 +910,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } else { abort_unless ( !sccs [i]->is_alive, - [&i] { return detail::_format_message ("Bridge SCC at index %d must NOT be alive", i); } + [&i] { return Util::monodroid_strdup_printf ("Bridge SCC at index %d must NOT be alive", i); } ); } } diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index aa5df834a37..311c00e9f27 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -19,77 +18,33 @@ #include -namespace xamarin::android::detail { - [[gnu::always_inline, gnu::flatten]] - static inline const char* - _format_message (const char *format, ...) noexcept - { - va_list ap; - va_start (ap, format); + +static inline void +do_abort_unless (const char* fmt, ...) +{ + va_list ap; char *message; int ret = vasprintf (&message, format, ap); - va_end (ap); - return ret == -1 ? "Out of memory" : message; - } - - [[gnu::always_inline]] - static inline std::string get_function_name (const char *signature) - { - using std::operator""sv; - - std::string_view sig { signature }; - if (sig.length () == 0) { - return ""; - } - - auto splitSignature = sig | std::views::split ("::"sv) | std::ranges::to> (); - - std::string ret; - if (splitSignature.size () > 1) { - ret.append (splitSignature [splitSignature.size () - 2]); - ret.append ("::"sv); - } - std::string_view func_name { splitSignature[splitSignature.size () - 1] }; - std::string_view::size_type args_pos = func_name.find ('('); - std::string_view::size_type name_start_pos = func_name.find (' '); - - if (name_start_pos == std::string_view::npos) { - name_start_pos = 0; - } else { - name_start_pos++; // point to after the space which separates return type from name - if (name_start_pos >= func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - } - - if (args_pos == std::string_view::npos) { - ret.append (func_name.substr (name_start_pos)); - } else { - // If there's a snafu with positions, start from 0 - if (name_start_pos >= args_pos || name_start_pos > func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - - ret.append (func_name.substr (name_start_pos, args_pos - name_start_pos)); - } - - return ret; - } + xamarin::android::Helpers::abort_application (n == -1 ? "Unable to allocate memory for abort message" : message); } +// #define abort_unless(_condition_, _fmt_, ...) \ +// if (!(_condition_)) [[unlikely]] { \ +// do_abort_unless ("%s:%d (%s): " _fmt_, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ +// } + template F> [[gnu::always_inline, gnu::flatten]] static inline void abort_unless (bool condition, F&& get_message, std::source_location sloc = std::source_location::current ()) noexcept { - static_assert (std::is_same::type, const char*>::value, "get_message must return 'const char*'"); - if (condition) [[likely]] { return; } +// static_assert (std::is_same, char*>::value, "get_message must return 'char*'"); xamarin::android::Helpers::abort_application (std::invoke (get_message), true /* log_location */, sloc); } @@ -103,39 +58,22 @@ abort_unless (bool condition, const char *message, std::source_location sloc = s xamarin::android::Helpers::abort_application (message, true /* log_location */, sloc); } +// #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_) + template [[gnu::always_inline, gnu::flatten]] static inline void abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless ( - ptr != nullptr, - [&ptr_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a valid pointer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - ptr_name - ); - }, - sloc - ); + abort_unless (ptr != nullptr, "Parameter '%s' must be a valid pointer", sloc); } [[gnu::always_inline, gnu::flatten]] static inline void abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless ( - arg > 0, - [&arg_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a positive integer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - arg_name - ); - }, - sloc - ); + abort_unless (arg > 0, "Parameter '%s' must be a valid pointer", sloc); } // Helper to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any From b2ac7803e1a18fe9048efe79acb04f05c38d9383 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 4 Nov 2024 20:55:16 +0100 Subject: [PATCH 005/143] More consistent use of std::string_view + remove unused code --- .../mono/monodroid/embedded-assemblies.hh | 15 +++---- src/native/mono/monodroid/monodroid-glue.cc | 7 +++- src/native/mono/monodroid/osbridge.cc | 6 +-- .../mono/runtime-base/shared-constants.hh | 3 +- src/native/mono/runtime-base/util.hh | 2 +- src/native/mono/shared/cpp-util.hh | 40 +++++++++++-------- 6 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index d78fa6755e1..9db6db7c4a8 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -92,9 +92,7 @@ namespace xamarin::android::internal { static constexpr size_t assemblies_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator); static constexpr auto assemblies_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator); - - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; + static constexpr std::string_view assemblies_prefix { assemblies_prefix_array }; // We have two records for each assembly, for names with and without the extension static constexpr uint32_t assembly_store_index_entries_per_assembly = 2; @@ -107,14 +105,11 @@ namespace xamarin::android::internal { static constexpr size_t assembly_store_file_name_size = calc_size (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_name_array = concat_string_views (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array.data () }; + static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array }; static constexpr size_t assembly_store_file_path_size = calc_size(apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_path_array = concat_string_views (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array.data () }; + static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array }; static constexpr size_t dso_size_overhead = ArchiveDSOStubConfig::PayloadSectionOffset + (ArchiveDSOStubConfig::SectionHeaderEntryCount * ArchiveDSOStubConfig::SectionHeaderEntrySize); @@ -173,8 +168,8 @@ namespace xamarin::android::internal { abort_unless ( runtime_config_data_size < std::numeric_limits::max (), [] { - return Util::monodroid_strdup_printf ("Runtime config binary blob size exceeds %u bytes", - std::numeric_limits::max ()); + return detail::_format_message ("Runtime config binary blob size exceeds %u bytes", + std::numeric_limits::max ()); } ); size = static_cast(runtime_config_data_size); diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index a5de62b9030..26547c8e476 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -917,7 +917,10 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( registerType != nullptr, [&error] { - return Util::monodroid_strdup_printf("INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", mono_error_get_message (&error)); + return detail::_format_message ( + "INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", + mono_error_get_message (&error) + ); } ); @@ -946,7 +949,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( initialize != nullptr, [&error] { - return Util::monodroid_strdup_printf ( + return detail::_format_message ( "Failed to obtain unmanaged-callers-only pointer to the Android.Runtime.JNIEnvInit.Initialize method. %s", mono_error_get_message (&error) ); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index c189efd5754..919506d3fda 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -880,9 +880,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (j > 0) { abort_unless ( sccs [i]->is_alive, - [&i] { - return Util::monodroid_strdup_printf ("Bridge SCC at index %d must be alive", i); - } + [&i] { return detail::_format_message ("Bridge SCC at index %d must be alive", i); } ); } sccs [i]->is_alive = 1; @@ -910,7 +908,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } else { abort_unless ( !sccs [i]->is_alive, - [&i] { return Util::monodroid_strdup_printf ("Bridge SCC at index %d must NOT be alive", i); } + [&i] { return detail::_format_message ("Bridge SCC at index %d must NOT be alive", i); } ); } } diff --git a/src/native/mono/runtime-base/shared-constants.hh b/src/native/mono/runtime-base/shared-constants.hh index 942b41fc964..c64680b2f83 100644 --- a/src/native/mono/runtime-base/shared-constants.hh +++ b/src/native/mono/runtime-base/shared-constants.hh @@ -46,8 +46,7 @@ namespace xamarin::android::internal static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); public: - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY.data () }; + static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY }; static constexpr std::string_view MONO_SGEN_SO { "libmonosgen-2.0.so" }; static constexpr std::string_view MONO_SGEN_ARCH_SO { "libmonosgen-" __BITNESS__ "-2.0.so" }; static constexpr std::string_view OVERRIDE_DIRECTORY_NAME { ".__override__" }; diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 33e9524703f..3dbdeae10bc 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -209,7 +209,7 @@ namespace xamarin::android } template - static bool ends_with (string_base const& str, std::array const& end) noexcept + static bool ends_with (internal::string_base const& str, std::array const& end) noexcept { constexpr size_t end_length = N - 1uz; diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index 311c00e9f27..f2f03b9d5b6 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -18,33 +19,33 @@ #include - -static inline void -do_abort_unless (const char* fmt, ...) -{ - va_list ap; +namespace xamarin::android::detail { + [[gnu::always_inline, gnu::flatten]] + static inline const char* + _format_message (const char *format, ...) noexcept + { + va_list ap; + va_start (ap, format); char *message; int ret = vasprintf (&message, format, ap); - xamarin::android::Helpers::abort_application (n == -1 ? "Unable to allocate memory for abort message" : message); + va_end (ap); + return ret == -1 ? "Out of memory" : message; + } } -// #define abort_unless(_condition_, _fmt_, ...) \ -// if (!(_condition_)) [[unlikely]] { \ -// do_abort_unless ("%s:%d (%s): " _fmt_, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ -// } - template F> [[gnu::always_inline, gnu::flatten]] static inline void abort_unless (bool condition, F&& get_message, std::source_location sloc = std::source_location::current ()) noexcept { + static_assert (std::is_same::type, const char*>::value, "get_message must return 'const char*'"); + if (condition) [[likely]] { return; } -// static_assert (std::is_same, char*>::value, "get_message must return 'char*'"); xamarin::android::Helpers::abort_application (std::invoke (get_message), true /* log_location */, sloc); } @@ -58,22 +59,27 @@ abort_unless (bool condition, const char *message, std::source_location sloc = s xamarin::android::Helpers::abort_application (message, true /* log_location */, sloc); } -// #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_) - template [[gnu::always_inline, gnu::flatten]] static inline void abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless (ptr != nullptr, "Parameter '%s' must be a valid pointer", sloc); + abort_unless ( + ptr != nullptr, + [&ptr_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", ptr_name); }, + sloc + ); } [[gnu::always_inline, gnu::flatten]] static inline void abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless (arg > 0, "Parameter '%s' must be a valid pointer", sloc); + abort_unless ( + arg > 0, + [&arg_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", arg_name); }, + sloc + ); } // Helper to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any From 66b192aa3b009ceb2d519146859bef0813bba2a3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 7 Nov 2024 14:13:30 +0100 Subject: [PATCH 006/143] Making EmbeddedAssemblies a static type In process to remove object instances for a slightly faster startup --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 2 +- src/native/mono/monodroid/embedded-assemblies.hh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 95c36da3f3c..2cb51ec75e2 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -581,7 +581,7 @@ EmbeddedAssemblies::zip_extract_cd_info (std::array const& buf } template -[[gnu::always_inline]] bool +force_inline bool EmbeddedAssemblies::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 9db6db7c4a8..8d76d55270c 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -208,8 +208,8 @@ namespace xamarin::android::internal { } private: - static const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; - static MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; + STATIC_IN_ANDROID_RELEASE const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; + STATIC_IN_ANDROID_RELEASE MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; static size_t register_from_apk (const char *apk_file, monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (const char *dir, bool look_for_mangled_names, monodroid_should_register should_register) noexcept; @@ -462,8 +462,8 @@ namespace xamarin::android::internal { static inline uint32_t number_of_zip_dso_entries = 0u; static inline bool need_to_scan_more_apks = true; - static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; - static inline xamarin::android::mutex assembly_decompress_mutex {}; + static inline AssemblyStoreIndexEntry *assembly_store_hashes; + static inline xamarin::android::mutex assembly_decompress_mutex; }; } From e8ff385fc2fca7c976f73586e0f44d81fd45d01e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 13 Nov 2024 10:58:18 -0800 Subject: [PATCH 007/143] More move to static, more cleanup --- src/native/mono/monodroid/embedded-assemblies.hh | 4 ++-- src/native/mono/monodroid/globals.cc | 1 + src/native/mono/monodroid/globals.hh | 1 + src/native/mono/monodroid/internal-pinvokes.cc | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 8d76d55270c..23fd7db733b 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -208,8 +208,8 @@ namespace xamarin::android::internal { } private: - STATIC_IN_ANDROID_RELEASE const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; - STATIC_IN_ANDROID_RELEASE MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; + static const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; + static MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; static size_t register_from_apk (const char *apk_file, monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (const char *dir, bool look_for_mangled_names, monodroid_should_register should_register) noexcept; diff --git a/src/native/mono/monodroid/globals.cc b/src/native/mono/monodroid/globals.cc index d5fdf4d08e4..7822952f8f0 100644 --- a/src/native/mono/monodroid/globals.cc +++ b/src/native/mono/monodroid/globals.cc @@ -4,6 +4,7 @@ using namespace xamarin::android; using namespace xamarin::android::internal; OSBridge osBridge; +MonodroidRuntime monodroidRuntime; Timing *timing = nullptr; Debug debug; diff --git a/src/native/mono/monodroid/globals.hh b/src/native/mono/monodroid/globals.hh index 046a0ff770f..6f1649d9796 100644 --- a/src/native/mono/monodroid/globals.hh +++ b/src/native/mono/monodroid/globals.hh @@ -11,6 +11,7 @@ extern xamarin::android::Debug debug; extern xamarin::android::internal::OSBridge osBridge; +extern xamarin::android::internal::MonodroidRuntime monodroidRuntime; extern xamarin::android::Timing *timing; #endif // !__GLOBALS_H diff --git a/src/native/mono/monodroid/internal-pinvokes.cc b/src/native/mono/monodroid/internal-pinvokes.cc index 41a98f6243d..ba5579c6140 100644 --- a/src/native/mono/monodroid/internal-pinvokes.cc +++ b/src/native/mono/monodroid/internal-pinvokes.cc @@ -18,7 +18,7 @@ int monodroid_embedded_assemblies_set_assemblies_prefix (const char *prefix) { EmbeddedAssemblies::set_assemblies_prefix (prefix); - return 0; + return 0; } void diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 26547c8e476..9e2350b779b 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -1271,7 +1271,7 @@ MonodroidRuntime::create_and_initialize_domain (JNIEnv* env, jclass runtimeClass abort_unless (default_alc != nullptr, "Default AssemblyLoadContext not found"); EmbeddedAssemblies::install_preload_hooks_for_alc (); - log_debug (LOG_ASSEMBLY, "ALC hooks installed"sv); + log_debug (LOG_ASSEMBLY, "ALC hooks installed"); bool preload = (AndroidSystem::is_assembly_preload_enabled () || (is_running_on_desktop && force_preload_assemblies)); From 20ddba5cf5e9a9c54ab71c63e876ff17e5e71721 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 13 Nov 2024 14:50:37 -0800 Subject: [PATCH 008/143] MonodroidRuntime is static now --- src/native/mono/monodroid/globals.cc | 1 - src/native/mono/monodroid/globals.hh | 1 - src/native/mono/monodroid/internal-pinvokes.cc | 7 +++++++ src/native/mono/monodroid/monodroid-glue.cc | 10 +++++----- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/native/mono/monodroid/globals.cc b/src/native/mono/monodroid/globals.cc index 7822952f8f0..d5fdf4d08e4 100644 --- a/src/native/mono/monodroid/globals.cc +++ b/src/native/mono/monodroid/globals.cc @@ -4,7 +4,6 @@ using namespace xamarin::android; using namespace xamarin::android::internal; OSBridge osBridge; -MonodroidRuntime monodroidRuntime; Timing *timing = nullptr; Debug debug; diff --git a/src/native/mono/monodroid/globals.hh b/src/native/mono/monodroid/globals.hh index 6f1649d9796..046a0ff770f 100644 --- a/src/native/mono/monodroid/globals.hh +++ b/src/native/mono/monodroid/globals.hh @@ -11,7 +11,6 @@ extern xamarin::android::Debug debug; extern xamarin::android::internal::OSBridge osBridge; -extern xamarin::android::internal::MonodroidRuntime monodroidRuntime; extern xamarin::android::Timing *timing; #endif // !__GLOBALS_H diff --git a/src/native/mono/monodroid/internal-pinvokes.cc b/src/native/mono/monodroid/internal-pinvokes.cc index ba5579c6140..a23bec07cf4 100644 --- a/src/native/mono/monodroid/internal-pinvokes.cc +++ b/src/native/mono/monodroid/internal-pinvokes.cc @@ -134,6 +134,13 @@ monodroid_clear_gdb_wait () MonodroidRuntime::set_monodroid_gdb_wait (false); } +void* +_monodroid_get_identity_hash_code (JNIEnv *env, void *v) +{ + intptr_t rv = env->CallStaticIntMethod (MonodroidRuntime::get_java_class_System (), MonodroidRuntime::get_java_class_method_System_identityHashCode (), v); + return (void*) rv; +} + void* _monodroid_timezone_get_default_id () { diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 9e2350b779b..af51cec4348 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -774,7 +774,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks return domain; } -[[gnu::always_inline]] void +force_inline void MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info) noexcept { info->klass = klass; @@ -799,7 +799,7 @@ MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJava } } -[[gnu::always_inline]] void +force_inline void MonodroidRuntime::lookup_bridge_info (MonoImage *image, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info) noexcept { lookup_bridge_info ( @@ -1302,7 +1302,7 @@ MonodroidRuntime::typemap_managed_to_java (MonoReflectionType *type, const uint8 } #endif // !def RELEASE -[[gnu::always_inline]] void +force_inline void MonodroidRuntime::setup_mono_tracing (std::unique_ptr const& mono_log_mask, bool have_log_assembly, bool have_log_gc) noexcept { constexpr std::string_view MASK_ASM { "asm" }; @@ -1375,7 +1375,7 @@ MonodroidRuntime::setup_mono_tracing (std::unique_ptr const& mono_log_ma mono_trace_set_mask_string (input_log_mask.get ()); } -[[gnu::always_inline]] void +force_inline void MonodroidRuntime::install_logging_handlers () noexcept { mono_trace_set_log_handler (mono_log_handler, nullptr); @@ -1607,7 +1607,7 @@ Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, ); } -[[gnu::always_inline]] void +force_inline void MonodroidRuntime::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods) noexcept { size_t total_time_index; From 2721778f44aba2856477d119994c565981956a12 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 13 Nov 2024 16:33:44 -0800 Subject: [PATCH 009/143] Buglets fixed --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 4 ++-- src/native/mono/monodroid/embedded-assemblies.hh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 2cb51ec75e2..54a0c7ab27a 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -267,7 +267,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& dynamic_local_string entry_name; bool assembly_store_found = false; - log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); + log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('%s')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -279,7 +279,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& continue; } - if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path)) { + if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path.data ())) { assembly_store_found = true; map_assembly_store (entry_name, state); continue; diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 23fd7db733b..9db6db7c4a8 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -462,8 +462,8 @@ namespace xamarin::android::internal { static inline uint32_t number_of_zip_dso_entries = 0u; static inline bool need_to_scan_more_apks = true; - static inline AssemblyStoreIndexEntry *assembly_store_hashes; - static inline xamarin::android::mutex assembly_decompress_mutex; + static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; + static inline xamarin::android::mutex assembly_decompress_mutex {}; }; } From d8814a52b2b879cf2816eba2df4b9a7cd1eca580 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 21 Nov 2024 14:06:41 +0100 Subject: [PATCH 010/143] Trying to find out why AppContext.GetData doesn't appear to work --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 9 +++++++++ src/native/mono/monodroid/monodroid-glue.cc | 5 ++++- src/native/mono/runtime-base/shared-constants.hh | 5 +++-- src/native/mono/runtime-base/util.hh | 5 +++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 54a0c7ab27a..925f64ff8cd 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -47,6 +47,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vectorstart_event (TimingEventKind::RuntimeConfigBlob); @@ -720,7 +721,9 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks runtime_config_args.kind = 1; EmbeddedAssemblies::get_runtime_config_blob (runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); - monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); + log_info (LOG_ASSEMBLY, " rc data == %p; rc size == %zu", runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); + int ret = monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); + log_info (LOG_ASSEMBLY, " ret == %d", ret); if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (blob_time_index); diff --git a/src/native/mono/runtime-base/shared-constants.hh b/src/native/mono/runtime-base/shared-constants.hh index c64680b2f83..3c4261af61e 100644 --- a/src/native/mono/runtime-base/shared-constants.hh +++ b/src/native/mono/runtime-base/shared-constants.hh @@ -40,13 +40,14 @@ namespace xamarin::android::internal static constexpr std::string_view DLL_EXTENSION { ".dll" }; static constexpr std::string_view PDB_EXTENSION { ".pdb" }; - private: +// private: static constexpr std::string_view RUNTIME_CONFIG_BLOB_BASE_NAME { "libarc.bin" }; static constexpr size_t runtime_config_blob_name_size = calc_size (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); public: - static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY }; + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY.data () }; static constexpr std::string_view MONO_SGEN_SO { "libmonosgen-2.0.so" }; static constexpr std::string_view MONO_SGEN_ARCH_SO { "libmonosgen-" __BITNESS__ "-2.0.so" }; static constexpr std::string_view OVERRIDE_DIRECTORY_NAME { ".__override__" }; diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 3dbdeae10bc..ea2b9f72f4e 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -168,6 +168,11 @@ namespace xamarin::android return false; } + log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", + str.get () + str.length () - sv.length (), + sv.data (), + sv.length () + ); return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; } From 5d230ee176fa89dc2d0bd6aca6d19e08ed96c1a0 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 21 Nov 2024 18:11:21 +0100 Subject: [PATCH 011/143] Cleanup --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 9 --------- src/native/mono/monodroid/embedded-assemblies.hh | 11 ++++++++--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 925f64ff8cd..54a0c7ab27a 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -47,7 +47,6 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator); - static constexpr std::string_view assemblies_prefix { assemblies_prefix_array }; + + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; // We have two records for each assembly, for names with and without the extension static constexpr uint32_t assembly_store_index_entries_per_assembly = 2; @@ -105,11 +107,14 @@ namespace xamarin::android::internal { static constexpr size_t assembly_store_file_name_size = calc_size (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_name_array = concat_string_views (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array }; + + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array.data () }; static constexpr size_t assembly_store_file_path_size = calc_size(apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_path_array = concat_string_views (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array }; + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array.data () }; static constexpr size_t dso_size_overhead = ArchiveDSOStubConfig::PayloadSectionOffset + (ArchiveDSOStubConfig::SectionHeaderEntryCount * ArchiveDSOStubConfig::SectionHeaderEntrySize); From c822af5f1f79fc66f37c27d4b46a7421f9b93216 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 25 Nov 2024 13:19:09 +0100 Subject: [PATCH 012/143] Lengths and offsets... --- src/native/mono/monodroid/internal-pinvokes.cc | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 5 +---- src/native/mono/runtime-base/shared-constants.hh | 2 +- src/native/mono/runtime-base/util.hh | 10 +++++----- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/native/mono/monodroid/internal-pinvokes.cc b/src/native/mono/monodroid/internal-pinvokes.cc index a23bec07cf4..7c3dbab4933 100644 --- a/src/native/mono/monodroid/internal-pinvokes.cc +++ b/src/native/mono/monodroid/internal-pinvokes.cc @@ -18,7 +18,7 @@ int monodroid_embedded_assemblies_set_assemblies_prefix (const char *prefix) { EmbeddedAssemblies::set_assemblies_prefix (prefix); - return 0; + return 0; } void diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 7e376ca9c3f..af51cec4348 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -713,7 +713,6 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks gather_bundled_assemblies (runtimeApks, &user_assemblies_count, have_split_apks); if (EmbeddedAssemblies::have_runtime_config_blob ()) { - log_info (LOG_ASSEMBLY, "Got runtime config blob"); size_t blob_time_index; if (FastTiming::enabled ()) [[unlikely]] { blob_time_index = internal_timing->start_event (TimingEventKind::RuntimeConfigBlob); @@ -721,9 +720,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks runtime_config_args.kind = 1; EmbeddedAssemblies::get_runtime_config_blob (runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); - log_info (LOG_ASSEMBLY, " rc data == %p; rc size == %zu", runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); - int ret = monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); - log_info (LOG_ASSEMBLY, " ret == %d", ret); + monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (blob_time_index); diff --git a/src/native/mono/runtime-base/shared-constants.hh b/src/native/mono/runtime-base/shared-constants.hh index 3c4261af61e..942b41fc964 100644 --- a/src/native/mono/runtime-base/shared-constants.hh +++ b/src/native/mono/runtime-base/shared-constants.hh @@ -40,7 +40,7 @@ namespace xamarin::android::internal static constexpr std::string_view DLL_EXTENSION { ".dll" }; static constexpr std::string_view PDB_EXTENSION { ".pdb" }; -// private: + private: static constexpr std::string_view RUNTIME_CONFIG_BLOB_BASE_NAME { "libarc.bin" }; static constexpr size_t runtime_config_blob_name_size = calc_size (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index ea2b9f72f4e..edd0e02f5ae 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -168,11 +168,11 @@ namespace xamarin::android return false; } - log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", - str.get () + str.length () - sv.length (), - sv.data (), - sv.length () - ); + // log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", + // str.get () + str.length () - sv.length (), + // sv.data (), + // sv.length () + // ); return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; } From 01f8460f773574bccfa5e493e6e1cf1cf5dd4b04 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 09:51:09 +0100 Subject: [PATCH 013/143] Cleanup --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 2 +- src/native/mono/runtime-base/util.hh | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 54a0c7ab27a..bf6a4efc305 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -279,7 +279,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& continue; } - if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path.data ())) { + if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path)) { assembly_store_found = true; map_assembly_store (entry_name, state); continue; diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index edd0e02f5ae..3dbdeae10bc 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -168,11 +168,6 @@ namespace xamarin::android return false; } - // log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", - // str.get () + str.length () - sv.length (), - // sv.data (), - // sv.length () - // ); return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; } From 2b9bd9ca05b137a36d43fd71851c878de672b8f2 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 19:02:12 +0100 Subject: [PATCH 014/143] Start using std::format and std::string_view string literals --- src/native/common/include/shared/log_level.hh | 133 ++++++++ .../mono/monodroid/embedded-assemblies-zip.cc | 76 ++--- .../mono/monodroid/embedded-assemblies.cc | 287 +++++++----------- .../mono/monodroid/embedded-assemblies.hh | 8 +- 4 files changed, 280 insertions(+), 224 deletions(-) diff --git a/src/native/common/include/shared/log_level.hh b/src/native/common/include/shared/log_level.hh index fc7a7566910..285255f649d 100644 --- a/src/native/common/include/shared/log_level.hh +++ b/src/native/common/include/shared/log_level.hh @@ -1,8 +1,34 @@ #pragma once #include +#include +#include +#include + +#include "java-interop-logger.h" + +// We redeclare macros as real functions here +#if defined(DO_LOG) +#undef DO_LOG +#endif + +#if defined(log_debug) +#undef log_debug +#endif + +#if defined(log_info) +#undef log_info +#endif namespace xamarin::android { + namespace detail { + [[gnu::always_inline]] + static inline bool _category_is_enabled (LogCategories category) noexcept + { + return (log_categories & category) == category; + } + } + enum class LogTimingCategories : uint32_t { Default = 0, @@ -23,4 +49,111 @@ namespace xamarin::android { 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; + + template [[gnu::always_inline]] + static inline constexpr void log_debug (LogCategories category, const char *format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_debug_nocheck (category, format, std::forward(args)...); + } + } + + template [[gnu::always_inline]] + static inline constexpr void log_debug (LogCategories category, std::string_view const& format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_debug_nocheck (category, format.data (), std::forward(args)...); + } + } + + static inline constexpr void log_debug (LogCategories category, std::string const& message) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_debug_nocheck (category, message.c_str ()); + } + } + + // + // This will be enabled once all log_* calls are converted to std::format format + // + // template [[gnu::always_inline]] + // static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) + // { + // if (detail::_category_is_enabled (category)) { + + // log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); + // } + // } + + template [[gnu::always_inline]] + static inline constexpr void log_info (LogCategories category, const char *format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, format, std::forward(args)...); + } + } + + template [[gnu::always_inline]] + static inline constexpr void log_info (LogCategories category, std::string_view const& format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, format.data (), std::forward(args)...); + } + } + + [[gnu::always_inline]] + static inline constexpr void log_info (LogCategories category, std::string const& message) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, message.c_str ()); + } + } + + [[gnu::always_inline]] + static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, message.c_str ()); + } + } + + [[gnu::always_inline]] + static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept + { + ::log_warn (category, message.c_str ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept + { + ::log_warn (category, message.data ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept + { + ::log_error (category, message.c_str ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept + { + ::log_error (category, message.data ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept + { + ::log_fatal (category, message.c_str ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept + { + ::log_fatal (category, message.data ()); + } } diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index bf6a4efc305..60a0658786f 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -22,7 +22,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector } auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (assembly_store_map, entry_name.get ()); - log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); + log_debug (LOG_ASSEMBLY, std::format ("Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size)); auto header = static_cast(payload_start); if (header->magic != ASSEMBLY_STORE_MAGIC) { @@ -227,7 +224,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string LOG_ASSEMBLY, std::format ( "Assembly store '{}' is not a valid .NET for Android assembly store file", - optional_string (entry_name.get ()) + entry_name.get () ) ); } @@ -237,7 +234,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string LOG_ASSEMBLY, std::format ( "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", - optional_string (entry_name.get ()), + entry_name.get (), header->version, ASSEMBLY_STORE_FORMAT_VERSION ) @@ -267,7 +264,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& dynamic_local_string entry_name; bool assembly_store_found = false; - log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('%s')", assembly_store_file_path.data ()); + log_debug (LOG_ASSEMBLY, std::format ("Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ())); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -303,12 +300,14 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& log_debug ( LOG_ASSEMBLY, - "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", - optional_string (entry_name.get ()), - number_of_zip_dso_entries, - optional_string (name), - apk_entry->name_hash, - apk_entry->offset + std::format ( + "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", + entry_name.get (), + number_of_zip_dso_entries, + name, + apk_entry->name_hash, + apk_entry->offset + ) ); number_of_zip_dso_entries++; } @@ -412,10 +411,9 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, - "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", - optional_string (entry.file_name), - optional_string (entry.name), - entry.data_size + std::format ("Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", + entry.file_name, entry.name, entry.data_size + ) ); } @@ -437,14 +435,14 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ // The simplest case - no file comment off_t ret = ::lseek (fd, -ZIP_EOCD_LEN, SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); return false; } std::array eocd; ssize_t nread = ::read (fd, eocd.data (), eocd.size ()); if (nread < 0 || nread != eocd.size ()) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); return false; } @@ -464,7 +462,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed ret = ::lseek (fd, static_cast(-alloc_size), SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); return false; } @@ -473,7 +471,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ nread = ::read (fd, buf.data (), buf.size ()); if (nread < 0 || static_cast(nread) != alloc_size) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); return false; } @@ -507,8 +505,10 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no if (result < 0) { log_error ( LOG_ASSEMBLY, - "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", - state.local_header_offset, std::strerror (errno), result, errno + std::format ( + "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", + state.local_header_offset, std::strerror (errno), result, errno + ) ); return false; } @@ -518,32 +518,32 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); if (nread < 0 || nread != ZIP_LOCAL_LEN) { - log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, std::format ("Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno)); return false; } size_t index = 0; if (!zip_read_field (local_header, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header entry signature at offset {}", state.local_header_offset)); return false; } if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, std::format ("Invalid Local Header entry signature at offset {}", state.local_header_offset)); return false; } uint16_t file_name_length; index = LH_FILE_NAME_LENGTH_OFFSET; if (!zip_read_field (local_header, index, file_name_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index))); return false; } uint16_t extra_field_length; index = LH_EXTRA_LENGTH_OFFSET; if (!zip_read_field (local_header, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index))); return false; } @@ -585,7 +585,7 @@ force_inline bool EmbeddedAssemblies::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { - log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); + log_error (LOG_ASSEMBLY, std::format ("Buffer too short to read {} bytes of data", to_read)); return false; } diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 95582ce2cc6..1ce0d2b1dbb 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -124,13 +124,13 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!", - optional_string (name), + name, cad.uncompressed_file_size, header->uncompressed_length ) ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", optional_string (name)); + log_debug (LOG_ASSEMBLY, std::format ("Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name)); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -143,7 +143,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} failed with code {}", - optional_string (name), + name, ret ) ); @@ -154,7 +154,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} yielded a different size (expected {}, got {})", - optional_string (name), + name, cad.uncompressed_file_size, static_cast(ret) ) @@ -228,7 +228,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", optional_string (file.name)); + log_debug (LOG_ASSEMBLY, std::format ("Assembly {} already mmapped by another thread, unmapping our copy", file.name)); munmap (map_info.area, file.data_size); map_info.area = nullptr; } @@ -243,16 +243,18 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc header[j] = isprint (p [j]) ? p [j] : '.'; header [header.size () - 1] = '\0'; - log_info_nocheck_fmt ( + log_info_nocheck ( LOG_ASSEMBLY, - "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", - file.data_offset, - static_cast(file.data), - pointer_add (file.data, file.data_size), - file.data_size, - optional_string (file.name), - optional_string (file.name), - header.data () + std::format ( + "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", + file.data_offset, + static_cast(file.data), + reinterpret_cast(file.data + file.data_size), + file.data_size, + file.name, + file.name, + header.data () + ) ); } } @@ -287,7 +289,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (strcmp (assembly.name, abi_name.get ()) != 0) { return nullptr; } else { - log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", optional_string (abi_name.get ())); + log_debug (LOG_ASSEMBLY, std::format ("open_from_bundles: found architecture-specific: '{}'", abi_name.get ())); } } @@ -321,7 +323,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (debug_file.data != nullptr) { if (debug_file.data_size > std::numeric_limits::max ()) { - log_warn (LOG_ASSEMBLY, "Debug info file '{}' is too big for Mono to consume", optional_string (debug_file.name)); + log_warn (LOG_ASSEMBLY, std::format ("Debug info file '{}' is too big for Mono to consume", debug_file.name)); } else { mono_debug_open_image_from_memory (image, reinterpret_cast(debug_file.data), static_cast(debug_file.data_size)); } @@ -333,7 +335,7 @@ EmbeddedAssemblies::load_bundled_assembly ( MonoImageOpenStatus status; MonoAssembly *a = mono_assembly_load_from_full (image, name.get (), &status, ref_only); if (a == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (name.get ()), optional_string (mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", name.get (), mono_image_strerror (status))); return nullptr; } @@ -348,7 +350,7 @@ EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_strin name.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", optional_string (name.get ())); + log_debug (LOG_ASSEMBLY, std::format ("individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ())); dynamic_local_string abi_name; abi_name @@ -395,11 +397,11 @@ template EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { hash_t name_hash = xxhash::hash (name.get (), name.length ()); - log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", optional_string (name.get ()), name_hash); + log_debug (LOG_ASSEMBLY, std::format ("assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash)); const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) { - log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.get ()), name_hash); + log_warn (LOG_ASSEMBLY, std::format ("Assembly '{}' (hash {:x}) not found", name.get (), name_hash)); return nullptr; } @@ -428,15 +430,16 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string(assembly_runtime_info.image_data), - static_cast(assembly_runtime_info.debug_info_data), - static_cast(assembly_runtime_info.config_data), - static_cast(assembly_runtime_info.descriptor), - assembly_runtime_info.descriptor->data_size, - assembly_runtime_info.descriptor->debug_data_size, - assembly_runtime_info.descriptor->config_data_size, - optional_string (name.get ()) + std::format ("Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'", + static_cast(assembly_runtime_info.image_data), + static_cast(assembly_runtime_info.debug_info_data), + static_cast(assembly_runtime_info.config_data), + static_cast(assembly_runtime_info.descriptor), + assembly_runtime_info.descriptor->data_size, + assembly_runtime_info.descriptor->debug_data_size, + assembly_runtime_info.descriptor->config_data_size, + name.get () + ) ); } @@ -446,7 +449,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string 0) { @@ -620,26 +623,26 @@ EmbeddedAssemblies::typemap_java_to_managed ([[maybe_unused]] hash_t hash, const entry = binary_search (java_type_name.get (), type_map.java_to_managed, type_map.entry_count); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ())); return nullptr; } const char *managed_type_name = entry->to; if (managed_type_name == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ()); + log_debug (LOG_ASSEMBLY, std::format ("typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ())); return nullptr; } - log_debug (LOG_DEFAULT, "typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), optional_string (managed_type_name)); + log_debug (LOG_DEFAULT, std::format ("typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), managed_type_name)); MonoType *type = mono_reflection_type_from_name (const_cast(managed_type_name), nullptr); if (type == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", optional_string (managed_type_name), java_type_name.get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ())); return nullptr; } 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 '{}'", optional_string (managed_type_name)); + log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type '{}'", managed_type_name)); return nullptr; } @@ -659,16 +662,16 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java TypeMapModule *module = java_entry != nullptr && java_entry->module_index < map_module_count ? &map_modules[java_entry->module_index] : nullptr; if (module == nullptr) { if (java_entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash)); } else { - log_warn (LOG_ASSEMBLY, "typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index); + log_warn (LOG_ASSEMBLY, std::format ("typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index)); } return nullptr; } const TypeMapModuleEntry *entry = binary_search (java_entry->type_token_id, module->map, module->entry_count); if (entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ())); return nullptr; } @@ -676,14 +679,14 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java module->image = mono_image_loaded (module->assembly_name); if (module->image == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", optional_string (module->assembly_name)); + log_debug (LOG_ASSEMBLY, std::format ("typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name)); // Fake a request from MonoVM to load the assembly. MonoAssemblyName *assembly_name = mono_assembly_name_new (module->assembly_name); MonoAssembly *assm; if (assembly_name == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: failed to create Mono assembly name for '{}'", optional_string (module->assembly_name)); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to create Mono assembly name for '{}'", module->assembly_name)); assm = nullptr; } else { MonoAssemblyLoadContextGCHandle alc_gchandle = mono_alc_get_default_gchandle (); @@ -692,28 +695,22 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (assm == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: failed to load managed assembly '{}'", optional_string (module->assembly_name)); + log_warn (LOG_ASSEMBLY, std::format ("typemap: failed to load managed assembly '{}'", module->assembly_name)); } else { module->image = mono_assembly_get_image (assm); } } if (module->image == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", optional_string (module->assembly_name), to_utf8 (java_type_name).get ()); + log_error (LOG_ASSEMBLY, std::format ("typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ())); return nullptr; } } - log_debug (LOG_ASSEMBLY, "typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); + log_debug (LOG_ASSEMBLY, std::format ("typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id)); MonoClass *klass = mono_class_get (module->image, java_entry->type_token_id); if (klass == nullptr) [[unlikely]] { - log_error ( - LOG_ASSEMBLY, - "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", - java_entry->type_token_id, - optional_string (module->assembly_name), - to_utf8 (java_type_name).get () - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); return nullptr; } @@ -724,12 +721,7 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java MonoReflectionType *ret = mono_type_get_object (domain, mono_class_get_type (klass)); if (ret == nullptr) { - log_warn (LOG_ASSEMBLY, - "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", - java_entry->type_token_id, - optional_string (module->assembly_name), - to_utf8 (java_type_name).get () - ); + log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); return nullptr; } @@ -794,7 +786,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapEntry *entry = typemap_managed_to_java (full_name.get ()); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", optional_string (full_name.get ())); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ())); return nullptr; } @@ -815,73 +807,57 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo if (mvid == nullptr) { log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); } else { - log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ())); } return nullptr; } uint32_t token = mono_class_get_type_token (klass); - log_debug (LOG_ASSEMBLY, "typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF); + log_debug (LOG_ASSEMBLY, std::format ("typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF)); // Each map entry is a pair of 32-bit integers: [TypeTokenID][JavaMapArrayIndex] const TypeMapModuleEntry *entry = match->map != nullptr ? binary_search (token, match->map, match->entry_count) : nullptr; if (entry == nullptr) { if (match->map == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ()); + log_warn (LOG_ASSEMBLY, std::format ("typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ())); return nullptr; } if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token); + log_debug (LOG_ASSEMBLY, std::format ("typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token)); entry = binary_search (token, match->duplicate_map, match->duplicate_count); } if (entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name); + log_info (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name)); return nullptr; } } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warn ( - LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", - token, - token, - MonoGuidString (mvid).get (), - optional_string (match->assembly_name), - entry->java_map_index - ); + log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index)); return nullptr; } TypeMapJava const& java_entry = map_java[entry->java_map_index]; if (java_entry.java_name_index >= java_type_count) [[unlikely]] { - log_warn ( - LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", - token, - token, - MonoGuidString (mvid).get (), - optional_string (match->assembly_name), - entry->java_map_index, - java_entry.java_name_index - ); + log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index)); return nullptr; } const char *ret = java_type_names[java_entry.java_name_index]; if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}", entry->java_map_index); + log_warn (LOG_ASSEMBLY, std::format ("typemap: empty Java type name returned for entry at index {}", entry->java_map_index)); } log_debug ( LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", - token, - token, - MonoGuidString (mvid).get (), - optional_string (match->assembly_name), - ret + std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", + token, + token, + MonoGuidString (mvid).get (), + match->assembly_name, + ret + ) ); return ret; @@ -943,15 +919,16 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons log_info ( LOG_ASSEMBLY, - " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + std::format (" mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", mmap_info.area, - pointer_add (mmap_info.area, mmap_info.size), + reinterpret_cast(reinterpret_cast (mmap_info.area) + mmap_info.size), mmap_info.size, file_info.area, - pointer_add (file_info.area, file_info.size), + reinterpret_cast(reinterpret_cast (file_info.area) + file_info.size), file_info.size, fd, - optional_string (filename) + filename + ) ); return file_info; @@ -967,11 +944,11 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro LOG_ASSEMBLY, std::format ( "ERROR: Unable to load application package {}.", - optional_string (apk) + apk ) ); } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk), fd); + log_debug (LOG_ASSEMBLY, std::format ("APK {} FD: {}", apk, fd)); zip_load_entries (fd, apk, should_register); } @@ -998,90 +975,40 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char struct stat sbuf; int res = fstatat (dir_fd, file_path, &sbuf, 0); if (res < 0) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to stat {} file '{}/{}': {}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); return false; } file_size = static_cast(sbuf.st_size); if (file_size < sizeof (header)) { - log_error ( - LOG_ASSEMBLY, - "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - sizeof (header) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header))); return false; } fd = openat (dir_fd, file_path, O_RDONLY); if (fd < 0) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to open {} file {}/{} for reading: {}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno))); return false; } ssize_t nread = do_read (fd, &header, sizeof (header)); if (nread <= 0) { if (nread < 0) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to read {} file header from '{}/{}': {}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); } else { - log_error ( - LOG_ASSEMBLY, - "typemap: end of file while reading {} file header from '{}/{}'", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path)); } return false; } if (header.magic != expected_magic) { - log_error ( - LOG_ASSEMBLY, - "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - expected_magic, - header.magic - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic)); return false; } if (header.version != MODULE_FORMAT_VERSION) { - log_error ( - LOG_ASSEMBLY, - "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", - optional_string (file_type), - MODULE_FORMAT_VERSION, - optional_string (dir_path), - optional_string (file_path), - header.version - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version)); return false; } @@ -1094,14 +1021,14 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ size_t entry_size = header.module_file_name_width; size_t data_size = entry_size * type_map_count; if (sizeof(header) + data_size > file_size) { - log_error (LOG_ASSEMBLY, "typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size); + log_error (LOG_ASSEMBLY, std::format ("typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size)); return nullptr; } auto data = std::make_unique (data_size); ssize_t nread = do_read (index_fd, data.get (), data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno)); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno))); return nullptr; } @@ -1117,7 +1044,7 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ std::unique_ptr EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", optional_string (dir_path), optional_string (index_path)); + log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap index file '{}/{}'", dir_path, index_path)); TypeMapIndexHeader header; size_t file_size; @@ -1144,13 +1071,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * ssize_t nread = do_read (file_fd, module.assembly_name, header.assembly_name_length); if (nread != static_cast(header.assembly_name_length)) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to read map assembly name from '{}/{}': {}", - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno))); return false; } @@ -1159,14 +1080,16 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, - "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", - optional_string (dir_path), - optional_string (file_path), - header.entry_count, - header.java_name_width, - header.managed_name_width, - header.assembly_name_length, - optional_string (module.assembly_name) + std::format ( + "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", + dir_path, + file_path, + header.entry_count, + header.java_name_width, + header.managed_name_width, + header.assembly_name_length, + module.assembly_name + ) ); // [name][index] @@ -1180,7 +1103,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * module.data = new uint8_t [data_size]; nread = do_read (file_fd, module.data, data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", optional_string (dir_path), optional_string (file_path), strerror (errno)); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno))); return false; } @@ -1224,7 +1147,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * bool EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMap &module) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", optional_string (dir_path), optional_string (file_path)); + log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap file '{}/{}'", dir_path, file_path)); bool ret = true; BinaryTypeMapHeader header; @@ -1263,7 +1186,7 @@ EmbeddedAssemblies::register_from_apk (const char *apk_file, monodroid_should_re gather_bundled_assemblies_from_apk (apk_file, should_register); - log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", optional_string (apk_file), number_of_found_assemblies - prev); + log_info (LOG_ASSEMBLY, std::format ("Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev)); return number_of_found_assemblies; } @@ -1367,10 +1290,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( [[gnu::always_inline]] size_t EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look_for_mangled_names, monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", optional_string (lib_dir_path)); + log_debug (LOG_ASSEMBLY, std::format ("Looking for assemblies in '{}'", lib_dir_path)); DIR *lib_dir = opendir (lib_dir_path); // TODO: put it in a scope guard at some point if (lib_dir == nullptr) { - log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno))); return 0; } @@ -1379,14 +1302,14 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno))); closedir (lib_dir); return 0; } state.file_fd = dup (dir_fd); if (state.file_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno))); closedir (lib_dir); return 0; } @@ -1403,7 +1326,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno))); continue; // keep going, no harm } break; // No more entries, we're done @@ -1423,7 +1346,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look // ...and we can handle the runtime config entry if (!runtime_config_blob_found && std::strncmp (cur->d_name, SharedConstants::RUNTIME_CONFIG_BLOB_NAME.data (), SharedConstants::RUNTIME_CONFIG_BLOB_NAME.size ()) == 0) { - log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", optional_string (cur->d_name)); + log_debug (LOG_ASSEMBLY, std::format ("Mapping runtime config blob from '{}'", cur->d_name)); auto file_size = Util::get_file_size_at (state.file_fd, cur->d_name); if (!file_size) { continue; @@ -1470,6 +1393,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, "Found {} assemblies on the filesystem", assembly_count); + log_debug (LOG_ASSEMBLY, std::format ("Found {} assemblies on the filesystem", assembly_count)); return assembly_count; } diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 8666dfc2f59..fe7493506fa 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -21,7 +21,7 @@ #include "archive-dso-stub-config.hh" #include "log_types.hh" -#include +#include "strings.hh" #include "xamarin-app.hh" #include #include "cppcompat.hh" @@ -310,7 +310,7 @@ namespace xamarin::android::internal { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", optional_string (file_name)); + log_debug (LOG_ASSEMBLY, std::format ("Not an ELF image: {}", file_name)); // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } @@ -329,7 +329,7 @@ namespace xamarin::android::internal { static void store_mapped_runtime_config_data (md_mmap_info const& map_info, const char *file_name) noexcept { auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (map_info, file_name); - log_debug (LOG_ASSEMBLY, "Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size); + log_debug (LOG_ASSEMBLY, std::format ("Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size)); runtime_config_data = payload_start; runtime_config_data_size = payload_size; runtime_config_blob_found = true; @@ -436,7 +436,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", optional_string (name.get ())); + log_debug (LOG_ASSEMBLY, std::format ("Unmangled name to '{}'", name.get ())); }; private: From b8599c0375e8fab1965ffabbff1914786edec631 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 22:55:24 +0100 Subject: [PATCH 015/143] A bit less of reinterpret_cast<> --- src/native/mono/monodroid/embedded-assemblies.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 1ce0d2b1dbb..2e7580dd398 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -249,7 +249,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", file.data_offset, static_cast(file.data), - reinterpret_cast(file.data + file.data_size), + pointer_add (file.data, file.data_size), file.data_size, file.name, file.name, @@ -921,10 +921,10 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons LOG_ASSEMBLY, std::format (" mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", mmap_info.area, - reinterpret_cast(reinterpret_cast (mmap_info.area) + mmap_info.size), + pointer_add (mmap_info.area, mmap_info.size), mmap_info.size, file_info.area, - reinterpret_cast(reinterpret_cast (file_info.area) + file_info.size), + pointer_add (file_info.area, file_info.size), file_info.size, fd, filename From 633f9936c7d285fea5436d784a87f5c3744add4a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 27 Nov 2024 13:13:47 +0100 Subject: [PATCH 016/143] Conversion to std::format continues Build is broken atm --- src/native/common/include/shared/log_level.hh | 182 ++++++++---------- src/native/mono/monodroid/debug.cc | 61 +++--- .../mono/monodroid/embedded-assemblies-zip.cc | 6 +- src/native/mono/monodroid/monodroid-glue.cc | 79 ++++---- src/native/mono/monodroid/osbridge.cc | 161 +++++++++------- .../mono/monodroid/xamarin_getifaddrs.cc | 56 +++--- .../pinvoke-override-api-impl.hh | 12 +- .../mono/pinvoke-override/precompiled.cc | 12 +- .../mono/runtime-base/android-system.cc | 64 +++--- src/native/mono/runtime-base/monodroid-dl.hh | 12 +- 10 files changed, 315 insertions(+), 330 deletions(-) diff --git a/src/native/common/include/shared/log_level.hh b/src/native/common/include/shared/log_level.hh index 285255f649d..e11dc18dae9 100644 --- a/src/native/common/include/shared/log_level.hh +++ b/src/native/common/include/shared/log_level.hh @@ -7,11 +7,7 @@ #include "java-interop-logger.h" -// We redeclare macros as real functions here -#if defined(DO_LOG) -#undef DO_LOG -#endif - +// We redeclare macros here #if defined(log_debug) #undef log_debug #endif @@ -20,15 +16,17 @@ #undef log_info #endif -namespace xamarin::android { - namespace detail { - [[gnu::always_inline]] - static inline bool _category_is_enabled (LogCategories category) noexcept - { - return (log_categories & category) == category; - } - } +#define DO_LOG_FMT(_level, _category_, _message_) \ + do { \ + if ((log_categories & ((_category_))) != 0) { \ + ::log_ ## _level ## _nocheck ((_category_), _message_); \ + } \ + } while (0) + +#define log_debug(_category_, _message_) DO_LOG_FMT (debug, (_category_), (_message_)) +#define log_info(_category_, _message_) DO_LOG_FMT (info, (_category_), (_message_)) +namespace xamarin::android { enum class LogTimingCategories : uint32_t { Default = 0, @@ -53,107 +51,79 @@ namespace xamarin::android { // 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; +} - template [[gnu::always_inline]] - static inline constexpr void log_debug (LogCategories category, const char *format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_debug_nocheck (category, format, std::forward(args)...); - } - } - - template [[gnu::always_inline]] - static inline constexpr void log_debug (LogCategories category, std::string_view const& format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_debug_nocheck (category, format.data (), std::forward(args)...); - } - } - - static inline constexpr void log_debug (LogCategories category, std::string const& message) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_debug_nocheck (category, message.c_str ()); - } - } - - // - // This will be enabled once all log_* calls are converted to std::format format - // - // template [[gnu::always_inline]] - // static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) - // { - // if (detail::_category_is_enabled (category)) { - - // log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); - // } - // } - - template [[gnu::always_inline]] - static inline constexpr void log_info (LogCategories category, const char *format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, format, std::forward(args)...); - } - } +// +// This will be enabled once all log_* calls are converted to std::format format +// +// template [[gnu::always_inline]] +// static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) +// { +// if (detail::_category_is_enabled (category)) { + +// log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); +// } +// } + +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Debug, message.c_str ()); +} - template [[gnu::always_inline]] - static inline constexpr void log_info (LogCategories category, std::string_view const& format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, format.data (), std::forward(args)...); - } - } +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Debug, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_info (LogCategories category, std::string const& message) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, message.c_str ()); - } - } +[[gnu::always_inline]] +static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Info, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, message.c_str ()); - } - } +[[gnu::always_inline]] +static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Info, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept - { - ::log_warn (category, message.c_str ()); - } +[[gnu::always_inline]] +static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept - { - ::log_warn (category, message.data ()); - } +[[gnu::always_inline]] +static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept - { - ::log_error (category, message.c_str ()); - } +[[gnu::always_inline]] +static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept - { - ::log_error (category, message.data ()); - } +[[gnu::always_inline]] +static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept - { - ::log_fatal (category, message.c_str ()); - } +[[gnu::always_inline]] +static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept - { - ::log_fatal (category, message.data ()); - } +[[gnu::always_inline]] +static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); } + +extern unsigned int log_categories; +#endif // ndef LOG_LEVEL_HH diff --git a/src/native/mono/monodroid/debug.cc b/src/native/mono/monodroid/debug.cc index 492e114704b..18d355bfa84 100644 --- a/src/native/mono/monodroid/debug.cc +++ b/src/native/mono/monodroid/debug.cc @@ -95,9 +95,10 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (!found) log_warn (LOG_DEFAULT, - "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", - optional_string (mname.get ()), - optional_string (libname.get ()) + std::format ("The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", + mname.get (), + libname.get () + ) ); } @@ -109,7 +110,7 @@ bool Debug::load_profiler (void *handle, const char *desc, const char *symbol) { ProfilerInitializer func = reinterpret_cast (java_interop_lib_symbol (handle, symbol, nullptr)); - log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", optional_string (symbol), reinterpret_cast(func)); + log_warn (LOG_DEFAULT, std::format ("Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func))); if (func != nullptr) { func (desc); @@ -139,7 +140,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, "Connection options: '{}'", optional_string (options)); + log_info (LOG_DEFAULT, std::format ("Connection options: '{}'", options)); args = Util::monodroid_strsplit (options, ",", 0); @@ -149,12 +150,12 @@ Debug::parse_options (char *options, ConnOptions *opts) if (strstr (arg, "port=") == arg) { int port = atoi (arg + strlen ("port=")); if (port < 0 || port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid debug port value {}", port); + log_error (LOG_DEFAULT, std::format ("Invalid debug port value {}", port)); continue; } conn_port = static_cast(port); - log_info (LOG_DEFAULT, "XS port = {}", conn_port); + log_info (LOG_DEFAULT, std::format ("XS port = {}", conn_port)); } else if (strstr (arg, "timeout=") == arg) { char *endp; @@ -163,7 +164,7 @@ Debug::parse_options (char *options, ConnOptions *opts) if ((endp == arg) || (*endp != '\0')) log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, "Unknown connection option: '{}'", optional_string (arg)); + log_info (LOG_DEFAULT, std::format ("Unknown connection option: '{}'", arg)); } } } @@ -187,7 +188,7 @@ Debug::start_connection (char *options) cur_time = time (nullptr); if (opts.timeout_time && cur_time > opts.timeout_time) { - log_warn (LOG_DEBUGGER, "Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time); + log_warn (LOG_DEBUGGER, std::format ("Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time)); return DebuggerConnectionStatus::Unconnected; } @@ -198,7 +199,7 @@ Debug::start_connection (char *options) res = pthread_create (&conn_thread_id, nullptr, xamarin::android::conn_thread, this); if (res) { - log_error (LOG_DEFAULT, "Failed to create connection thread: {}", strerror (errno)); + log_error (LOG_DEFAULT, std::format ("Failed to create connection thread: {}", strerror (errno))); return DebuggerConnectionStatus::Error; } @@ -262,20 +263,20 @@ Debug::process_connection (int fd) return false; } if (rv <= 0) { - log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); return false; } rv = Util::recv_uninterrupted (fd, command, cmd_len); if (rv <= 0) { - log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); return false; } // null-terminate command [cmd_len] = 0; - log_info (LOG_DEFAULT, "Received cmd: '{}'.", optional_string (command)); + log_info (LOG_DEFAULT, std::format ("Received cmd: '{}'.", command)); if (process_cmd (fd, command)) return true; @@ -287,14 +288,14 @@ Debug::handle_server_connection (void) { int listen_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_socket == -1) { - log_info (LOG_DEFAULT, "Could not create socket for XS to connect to: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not create socket for XS to connect to: {}", strerror (errno))); return 1; } int flags = 1; int rv = setsockopt (listen_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); if (rv == -1 && Util::should_log (LOG_DEFAULT)) { - log_info_nocheck_fmt (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno)); + log_info_nocheck (LOG_DEFAULT, std::format ("Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno))); // not a fatal failure } @@ -308,7 +309,7 @@ Debug::handle_server_connection (void) listen_addr.sin_addr.s_addr = INADDR_ANY; rv = bind (listen_socket, (struct sockaddr *) &listen_addr, sizeof (listen_addr)); if (rv == -1) { - log_info (LOG_DEFAULT, "Could not bind to address: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not bind to address: {}", strerror (errno))); rv = 2; goto cleanup; } @@ -320,7 +321,7 @@ Debug::handle_server_connection (void) rv = listen (listen_socket, 1); if (rv == -1) { - log_info (LOG_DEFAULT, "Could not listen for XS: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not listen for XS: {}", strerror (errno))); rv = 2; goto cleanup; } @@ -370,7 +371,7 @@ Debug::handle_server_connection (void) } while (rv == -1 && errno == EINTR); if (rv == -1) { - log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Failed while waiting for XS to connect: {}", strerror (errno))); rv = 2; goto cleanup; } @@ -378,18 +379,18 @@ Debug::handle_server_connection (void) socklen_t len = sizeof (struct sockaddr_in); int fd = accept (listen_socket, (struct sockaddr *) &listen_addr, &len); if (fd == -1) { - log_info (LOG_DEFAULT, "Failed to accept connection from XS: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Failed to accept connection from XS: {}", strerror (errno))); rv = 3; goto cleanup; } flags = 1; if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flags, sizeof (flags)) < 0) { - log_info (LOG_DEFAULT, "Could not set TCP_NODELAY on socket ({})", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not set TCP_NODELAY on socket ({})", strerror (errno))); // not a fatal failure } - log_info (LOG_DEFAULT, "Successfully received connection from XS on port {}, fd: {}", listen_port, fd); + log_info (LOG_DEFAULT, std::format ("Successfully received connection from XS on port {}, fd: {}", listen_port, fd)); need_new_conn = process_connection (fd); } @@ -441,7 +442,7 @@ Debug::process_cmd (int fd, char *cmd) constexpr std::string_view PONG_REPLY { "pong" }; if (strcmp (cmd, PING_CMD.data ()) == 0) { 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 ({})", strerror (errno)); + log_error (LOG_DEFAULT, std::format ("Got keepalive request from XS, but could not send response back ({})", strerror (errno))); return false; } @@ -487,7 +488,7 @@ Debug::process_cmd (int fd, char *cmd) profiler_fd = fd; profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { - log_error (LOG_DEFAULT, "Unknown profiler: '{}'", optional_string (prof)); + log_error (LOG_DEFAULT, std::format ("Unknown profiler: '{}'", prof)); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -496,7 +497,7 @@ Debug::process_cmd (int fd, char *cmd) pthread_mutex_unlock (&process_cmd_mutex); return use_fd; } else { - log_error (LOG_DEFAULT, "Unsupported command: '{}'", optional_string (cmd)); + log_error (LOG_DEFAULT, std::format ("Unsupported command: '{}'", cmd)); } return false; @@ -526,7 +527,7 @@ Debug::start_debugging (void) // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); + log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); if (enable_soft_breakpoints ()) { constexpr std::string_view soft_breakpoints { "--soft-breakpoints" }; @@ -553,7 +554,7 @@ Debug::start_profiling () if (!profiler_description) return; - log_info (LOG_DEFAULT, "Loading profiler: '{}'", profiler_description); + log_info (LOG_DEFAULT, std::format ("Loading profiler: '{}'", profiler_description)); monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), profiler_description, nullptr); } @@ -573,7 +574,7 @@ Debug::enable_soft_breakpoints (void) uname (&name); for (const char** ptr = soft_breakpoint_kernel_list; *ptr; ptr++) { if (strcmp (name.release, *ptr) == 0) { - log_info (LOG_DEBUGGER, "soft breakpoints enabled due to kernel version match ({})", name.release); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled due to kernel version match ({})", name.release)); return 1; } } @@ -581,17 +582,17 @@ Debug::enable_soft_breakpoints (void) char *value; /* Soft breakpoints are enabled by default */ if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS, &value) <= 0) { - log_info (LOG_DEBUGGER, "soft breakpoints enabled by default ({} property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled by default ({} 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 ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); } else { ret = true; - log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); } delete[] value; return ret; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 60a0658786f..59069330dfb 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -331,9 +331,9 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ); } #ifdef DEBUG - log_info (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); - log_info (LOG_ASSEMBLY, "Central directory size: {}", cd_size); - log_info (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); + log_info (LOG_ASSEMBLY, std::format ("Central directory offset: {}", cd_offset)); + log_info (LOG_ASSEMBLY, std::format ("Central directory size: {}", cd_size)); + log_info (LOG_ASSEMBLY, std::format ("Central directory entries: {}", cd_entries)); #endif off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); if (retval < 0) { diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index af51cec4348..65cf8919eea 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -174,12 +174,12 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] fullpath.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", optional_string (fullpath.get ())); + log_debug (LOG_ASSEMBLY, std::format ("open_from_update_dir: trying to open assembly: {}", 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) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (fullpath.get ()), mono_image_strerror (status)); + log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status))); } } else { log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); @@ -191,7 +191,7 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] } if (result != nullptr && Util::should_log (LOG_ASSEMBLY)) { - log_info_nocheck_fmt (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result)); + log_info_nocheck (LOG_ASSEMBLY, std::format ("open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result))); } return result; } @@ -378,7 +378,7 @@ MonodroidRuntime::parse_gdb_options () noexcept time_t secs = time (nullptr); if (v + 10 < secs) { - log_warn (LOG_DEFAULT, "Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); + log_warn (LOG_DEFAULT, std::format ("Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ())); do_wait = false; } } @@ -449,13 +449,13 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid SDB port value {}", sdb_port); + log_error (LOG_DEFAULT, std::format ("Invalid SDB port value {}", sdb_port)); ret = false; continue; } if (out_port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid output port value {}", out_port); + log_error (LOG_DEFAULT, std::format ("Invalid output port value {}", out_port)); ret = false; continue; } @@ -480,7 +480,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string arg (token); - log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", optional_string (arg.get ())); + log_error (LOG_DEFAULT, std::format ("Unknown runtime argument: '{}'", arg.get ())); ret = false; } } @@ -509,9 +509,9 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse cur_time = time (nullptr); if (!parse_runtime_args (runtime_args, &options)) { - log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", optional_string (runtime_args.get ())); + log_error (LOG_DEFAULT, std::format ("Failed to parse runtime args: '{}'", runtime_args.get ())); } else if (options.debug && cur_time > options.timeout_time) { - log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time); + log_warn (LOG_DEBUGGER, std::format ("Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time)); } else if (options.debug && cur_time <= options.timeout_time) { EmbeddedAssemblies::set_register_debug_symbols (true); @@ -537,7 +537,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); + log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); if (options.out_port > 0) { int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -570,13 +570,13 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (options.server) { int accepted = monodroid_debug_accept (sock, addr); - log_warn (LOG_DEBUGGER, "Accepted stdout connection: {}", accepted); + log_warn (LOG_DEBUGGER, std::format ("Accepted stdout connection: {}", accepted)); if (accepted < 0) { Helpers::abort_application ( LOG_DEBUGGER, std::format ( "Error accepting stdout and stderr ({}:{}): {}", - optional_string (options.host), + options.host, options.out_port, strerror (errno) ) @@ -591,7 +591,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse LOG_DEBUGGER, std::format ( "Error connecting stdout and stderr ({}:{}): {}", - optional_string (options.host), + options.host, options.out_port, strerror (errno) ) @@ -662,7 +662,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; - log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", optional_string (prop_val.get ())); + log_warn (LOG_DEBUGGER, std::format ("passing '{}' as extra arguments to the runtime.", prop_val.get ())); char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; @@ -730,9 +730,11 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks 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 '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", - optional_string (AndroidSystem::override_dirs [0]), - (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? optional_string (AndroidSystem::override_dirs [1]) : "" + std::format ( + "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", + AndroidSystem::override_dirs [0], + (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv + ) ); #else log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"sv); @@ -741,7 +743,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks Helpers::abort_application ( std::format ( "ALL entries in APK named `{}` MUST be STORED. Gradle's minification may COMPRESS such entries.", - optional_string (assemblies_prefix) + assemblies_prefix ) ); } @@ -857,7 +859,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec // GC threshold is 90% of the max GREF count init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); - log_info (LOG_GC, "GREF GC Threshold: {}", init.grefGcThreshold); + log_info (LOG_GC, std::format ("GREF GC Threshold: {}", init.grefGcThreshold)); init.grefClass = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); @@ -943,7 +945,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec auto initialize = reinterpret_cast (mono_method_get_unmanaged_callers_only_ftnptr (method, &error)); if (initialize == nullptr) { - log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", optional_string (mono_error_get_message (&error))); + log_fatal (LOG_DEFAULT, std::format ("Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error))); } abort_unless ( @@ -999,7 +1001,7 @@ MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstr if (createDirectory) { 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 {}. {}", optional_string (name), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create directory for environment variable {}. {}", name, strerror (errno))); } setenv (name, value.get_cstr (), 1); } @@ -1009,10 +1011,10 @@ MonodroidRuntime::create_xdg_directory (jstring_wrapper& home, size_t home_len, { static_local_string dir (home_len + 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: {}", optional_string (dir.get ())); + log_debug (LOG_DEFAULT, std::format ("Creating XDG directory: {}", dir.get ())); int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", optional_string (dir.get ()), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create XDG directory {}. {}", dir.get (), strerror (errno))); if (!environment_variable_name.empty ()) { setenv (environment_variable_name.data (), dir.get (), 1); } @@ -1041,7 +1043,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", optional_string (name), optional_string (v)); + log_debug (LOG_DEFAULT, std::format ("Env variable '{}' set to '{}'.", name, v)); }; string_segment arg_token; @@ -1061,7 +1063,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept log_envvar (arg.get (), one.data ()); } else if (index == 0) { // ’=value’ - log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", optional_string (arg.get ())); + log_warn (LOG_DEFAULT, std::format ("Attempt to set environment variable without specifying name: '{}'", arg.get ())); } else { // ’name=value’ arg[index] = '\0'; @@ -1141,10 +1143,10 @@ MonodroidRuntime::set_profile_options () noexcept .append (output_path.get (), output_path.length ()); } if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno))); } - log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", optional_string (value.get ())); + log_warn (LOG_DEFAULT, std::format ("Initializing profiler with options: {}", value.get ())); debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } @@ -1271,7 +1273,7 @@ MonodroidRuntime::create_and_initialize_domain (JNIEnv* env, jclass runtimeClass abort_unless (default_alc != nullptr, "Default AssemblyLoadContext not found"); EmbeddedAssemblies::install_preload_hooks_for_alc (); - log_debug (LOG_ASSEMBLY, "ALC hooks installed"); + log_debug (LOG_ASSEMBLY, "ALC hooks installed"sv); bool preload = (AndroidSystem::is_assembly_preload_enabled () || (is_running_on_desktop && force_preload_assemblies)); @@ -1469,7 +1471,7 @@ 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: {}", optional_string (AndroidSystem::get_runtime_libdir ())); + log_debug (LOG_DEFAULT, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); } AndroidSystem::setup_process_args (runtimeApks); @@ -1534,14 +1536,15 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (Util::should_log (LOG_DEFAULT)) [[unlikely]] { log_info_nocheck_fmt ( LOG_DEFAULT, - ".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", - BuildInfo::xa_version.data (), - BuildInfo::architecture.data (), - BuildInfo::kind.data (), - BuildInfo::date.data (), - BuildInfo::ndk_version.data (), - BuildInfo::ndk_api_level.data (), - mono_get_runtime_build_info () + std::format (".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", + BuildInfo::xa_version.data (), + BuildInfo::architecture.data (), + BuildInfo::kind.data (), + BuildInfo::date.data (), + BuildInfo::ndk_version.data (), + BuildInfo::ndk_api_level.data (), + mono_get_runtime_build_info () + ) ); } @@ -1664,7 +1667,7 @@ MonodroidRuntime::get_java_class_name_for_TypeManager (jclass klass) noexcept JNIEnv *env = osBridge.ensure_jnienv (); jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); if (name == nullptr) { - log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); + log_error (LOG_DEFAULT, std::format ("Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass))); return nullptr; } diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 919506d3fda..612e6c44c5e 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -186,7 +186,7 @@ OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) *end = '\0'; if ((category == LOG_GREF && gref_to_logcat) || (category == LOG_LREF && lref_to_logcat)) { - log_debug (category, "{}", optional_string (m)); + log_debug (category, std::format ("{}", m)); } if (to != nullptr) { fprintf (to, "%s\n", optional_string (m)); @@ -200,7 +200,7 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, "{}", optional_string (message)); + log_debug (LOG_GREF, std::format ("{}", message)); } if (!gref_log) return; @@ -214,23 +214,23 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH int c = _monodroid_gref_inc (); if ((log_categories & LOG_GREF) == 0) return c; - log_info (LOG_GREF, - "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - optional_string (threadName), - threadId + std::format ("+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -261,19 +261,20 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -300,21 +301,22 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - optional_string (threadName), - threadId + std::format ("+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -343,19 +345,20 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -381,18 +384,19 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - "+l+ lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("+l+ lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!lref_log) @@ -417,18 +421,19 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - "-l- lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("-l- lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!lref_log) @@ -541,9 +546,11 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) i = get_gc_bridge_index (klass); if (i == static_cast (-NUM_GC_BRIDGE_TYPES)) { log_info (LOG_GC, - "asked if a class {}.{} is a bridge before we inited java.lang.Object", - optional_string (mono_class_get_namespace (klass)), - optional_string (mono_class_get_name (klass)) + std::format ( + "asked if a class {}.{} is a bridge before we inited java.lang.Object", + mono_class_get_namespace (klass), + mono_class_get_name (klass) + ) ); return MonoGCBridgeObjectKind::GC_BRIDGE_TRANSPARENT_CLASS; } @@ -569,9 +576,11 @@ OSBridge::gc_is_bridge_object (MonoObject *object) #if DEBUG MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, - "object of class {}.{} with null handle", - optional_string (mono_class_get_namespace (mclass)), - optional_string (mono_class_get_name (mclass)) + std::format ( + "object of class {}.{} with null handle", + mono_class_get_namespace (mclass), + mono_class_get_name (mclass) + ) ); #endif return 0; @@ -658,9 +667,9 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri *reffed_description = describe_target (reffed_target); if (success) - log_warn (LOG_GC, "Added reference for {} to {}", optional_string (description), optional_string (reffed_description)); + log_warn (LOG_GC, std::format ("Added reference for {} to {}", description, reffed_description)); else - log_error (LOG_GC, "Missing monodroidAddReference method for {}", optional_string (description)); + log_error (LOG_GC, std::format ("Missing monodroidAddReference method for {}", description)); free (description); free (reffed_description); @@ -897,9 +906,11 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (Logger::gc_spew_enabled ()) { klass = mono_object_get_class (obj); log_error (LOG_GC, - "Missing monodroidClearReferences method for object of class {}.{}", - optional_string (mono_class_get_namespace (klass)), - optional_string (mono_class_get_name (klass)) + std::format ( + "Missing monodroidClearReferences method for object of class {}.{}", + mono_class_get_namespace (klass), + mono_class_get_name (klass) + ) ); } #endif @@ -914,7 +925,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } } #if DEBUG - log_info (LOG_GC, "GC cleanup summary: {} objects tested - resurrecting {}.", total, alive); + log_info (LOG_GC, std::format ("GC cleanup summary: {} objects tested - resurrecting {}.", total, alive)); #endif } @@ -944,10 +955,10 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre if (Logger::gc_spew_enabled ()) { int i, j; - log_info (LOG_GC, "cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs); + log_info (LOG_GC, std::format ("cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs)); for (i = 0; i < num_sccs; ++i) { - log_info (LOG_GC, "group {} with {} objects", i, sccs [i]->num_objs); + log_info (LOG_GC, std::format ("group {} with {} objects", i, sccs [i]->num_objs)); for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; @@ -962,19 +973,21 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre } MonoClass *klass = mono_object_get_class (obj); log_info (LOG_GC, - "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", - reinterpret_cast(obj), - optional_string (mono_class_get_namespace (klass)), - optional_string (mono_class_get_name (klass)), - reinterpret_cast(handle), - key_handle + std::format ( + "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", + reinterpret_cast(obj), + mono_class_get_namespace (klass), + mono_class_get_name (klass), + reinterpret_cast(handle), + key_handle + ) ); } } if (Util::should_log (LOG_GC)) { for (i = 0; i < num_xrefs; ++i) - log_info_nocheck_fmt (LOG_GC, "xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); + log_info_nocheck (LOG_GC, std::format ("xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index)); } } diff --git a/src/native/mono/monodroid/xamarin_getifaddrs.cc b/src/native/mono/monodroid/xamarin_getifaddrs.cc index 23848f9910b..99ba01039e6 100644 --- a/src/native/mono/monodroid/xamarin_getifaddrs.cc +++ b/src/native/mono/monodroid/xamarin_getifaddrs.cc @@ -421,7 +421,7 @@ open_netlink_session (netlink_session *session) memset (session, 0, sizeof (*session)); session->sock_fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (session->sock_fd == -1) { - log_warn (LOG_NETLINK, "Failed to create a netlink socket. {}", strerror (errno)); + log_warn (LOG_NETLINK, std::format ("Failed to create a netlink socket. {}", strerror (errno))); return -1; } @@ -440,7 +440,7 @@ open_netlink_session (netlink_session *session) session->them.nl_family = AF_NETLINK; if (bind (session->sock_fd, (struct sockaddr *)&session->us, sizeof (session->us)) < 0) { - log_warn (LOG_NETLINK, "Failed to bind to the netlink socket. {}", strerror (errno)); + log_warn (LOG_NETLINK, std::format ("Failed to bind to the netlink socket. {}", strerror (errno))); return -1; } @@ -478,7 +478,7 @@ send_netlink_dump_request (netlink_session *session, int type) session->message_header.msg_iov = &session->payload_vector; if (sendmsg (session->sock_fd, (const struct msghdr*)&session->message_header, 0) < 0) { - log_warn (LOG_NETLINK, "Failed to send netlink message. {}", strerror (errno)); + log_warn (LOG_NETLINK, std::format ("Failed to send netlink message. {}", strerror (errno))); return -1; } @@ -529,7 +529,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd abort_if_invalid_pointer_argument (last_ifaddr, "last_ifaddr"); size_t buf_size = static_cast(getpagesize ()); - log_debug (LOG_NETLINK, "receive buffer size == {}", buf_size); + log_debug (LOG_NETLINK, std::format ("receive buffer size == {}", buf_size)); size_t alloc_size = Helpers::multiply_with_overflow_check (sizeof(*response), buf_size); response = (unsigned char*)malloc (alloc_size); @@ -551,10 +551,10 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd netlink_reply.msg_iov = &reply_vector; length = recvmsg (session->sock_fd, &netlink_reply, 0); - log_debug (LOG_NETLINK, " length == {}", (int)length); + log_debug (LOG_NETLINK, std::format (" length == {}", (int)length)); if (length < 0) { - log_debug (LOG_NETLINK, "Failed to receive reply from netlink. {}", strerror (errno)); + log_debug (LOG_NETLINK, std::format ("Failed to receive reply from netlink. {}", strerror (errno))); goto cleanup; } @@ -582,7 +582,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; for (current_message = (struct nlmsghdr*)response; current_message && NLMSG_OK (current_message, static_cast(length)); current_message = NLMSG_NEXT (current_message, length)) { - log_debug (LOG_NETLINK, "next message... (type: {})", current_message->nlmsg_type); + log_debug (LOG_NETLINK, std::format ("next message... (type: {})", current_message->nlmsg_type)); switch (current_message->nlmsg_type) { /* See rtnetlink.h */ case RTM_NEWLINK: @@ -611,7 +611,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; default: - log_debug (LOG_NETLINK, " message type: {}", current_message->nlmsg_type); + log_debug (LOG_NETLINK, std::format (" message type: {}", current_message->nlmsg_type)); break; } } @@ -634,7 +634,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET: { struct sockaddr_in *sa4; if (rta_payload_length != 4) /* IPv4 address length */ { - log_warn (LOG_NETLINK, "Unexpected IPv4 address payload length {}", rta_payload_length); + log_warn (LOG_NETLINK, std::format ("Unexpected IPv4 address payload length {}", rta_payload_length)); return -1; } sa4 = (struct sockaddr_in*)calloc (1, sizeof (*sa4)); @@ -650,7 +650,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET6: { struct sockaddr_in6 *sa6; if (rta_payload_length != 16) /* IPv6 address length */ { - log_warn (LOG_NETLINK, "Unexpected IPv6 address payload length {}", rta_payload_length); + log_warn (LOG_NETLINK, std::format ("Unexpected IPv6 address payload length {}", rta_payload_length)); return -1; } sa6 = (struct sockaddr_in6*)calloc (1, sizeof (*sa6)); @@ -668,7 +668,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ default: { struct sockaddr *sagen; if (rta_payload_length > sizeof (sagen->sa_data)) { - log_warn (LOG_NETLINK, "Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data)); + log_warn (LOG_NETLINK, std::format ("Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data))); return -1; } @@ -701,9 +701,9 @@ fill_ll_address (struct sockaddr_ll_extended **sa, struct ifinfomsg *net_interfa /* The assert can only fail for Iniband links, which are quite unlikely to be found * in any mobile devices */ - log_debug (LOG_NETLINK, "rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type); + log_debug (LOG_NETLINK, std::format ("rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type)); if (static_cast(rta_payload_length) > sizeof ((*sa)->sll_addr)) { - log_info (LOG_NETLINK, "Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr)); + log_info (LOG_NETLINK, std::format ("Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr))); free (*sa); *sa = NULL; return -1; @@ -817,14 +817,14 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net memset (netmask_data, 0xFF, prefix_bytes); if (postfix_bytes > 0) memset (netmask_data + prefix_bytes + 1, 0x00, postfix_bytes); - log_debug (LOG_NETLINK, " calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length); + log_debug (LOG_NETLINK, std::format (" calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length)); 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 (Util::should_log (LOG_NETLINK)) { log_debug_nocheck (LOG_NETLINK, " netmask is: "sv); for (uint32_t i = 0; i < data_length; i++) { - log_debug_nocheck_fmt (LOG_NETLINK, "{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i]); + log_debug_nocheck (LOG_NETLINK, std::format ("{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i])); } } } @@ -847,7 +847,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if abort_if_invalid_pointer_argument (message, "message"); net_address = reinterpret_cast (NLMSG_DATA (message)); length = static_cast(IFA_PAYLOAD (message)); - log_debug (LOG_NETLINK, " address data length: {}", length); + log_debug (LOG_NETLINK, std::format (" address data length: {}", length)); if (length <= 0) { goto error; } @@ -864,7 +864,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " reading attributes"sv); while (RTA_OK (attribute, length)) { payload_size = RTA_PAYLOAD (attribute); - log_debug (LOG_NETLINK, " attribute payload_size == {}", payload_size); + log_debug (LOG_NETLINK, std::format (" attribute payload_size == {}", payload_size)); sa = NULL; switch (attribute->rta_type) { @@ -943,7 +943,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; default: - log_debug (LOG_NETLINK, " attribute type: {}", attribute->rta_type); + log_debug (LOG_NETLINK, std::format (" attribute type: {}", attribute->rta_type)); break; } @@ -962,7 +962,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " address has no name/label, getting one from interface"sv); ifa->ifa_name = name ? strdup (name) : NULL; } - log_debug (LOG_NETLINK, " address label: {}", optional_string (ifa->ifa_name)); + log_debug (LOG_NETLINK, std::format (" address label: {}", ifa->ifa_name)); if (calculate_address_netmask (ifa, net_address) < 0) { goto error; @@ -1016,13 +1016,13 @@ get_link_info (const struct nlmsghdr *message) goto error; } if (Util::should_log (LOG_NETLINK)) { - log_debug_nocheck_fmt (LOG_NETLINK, " interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); - log_debug_nocheck_fmt (LOG_NETLINK, " {}", optional_string (ifa->ifa_name)); + log_debug_nocheck (LOG_NETLINK, std::format (" interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name))); + log_debug_nocheck (LOG_NETLINK, std::format (" {}", ifa->ifa_name)); } break; case IFLA_BROADCAST: - log_debug (LOG_NETLINK, " interface broadcast ({} bytes)", RTA_PAYLOAD (attribute)); + log_debug (LOG_NETLINK, std::format (" interface broadcast ({} bytes)", RTA_PAYLOAD (attribute))); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1030,7 +1030,7 @@ get_link_info (const struct nlmsghdr *message) break; case IFLA_ADDRESS: - log_debug (LOG_NETLINK, " interface address ({} bytes)", RTA_PAYLOAD (attribute)); + log_debug (LOG_NETLINK, std::format (" interface address ({} bytes)", RTA_PAYLOAD (attribute))); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1047,7 +1047,7 @@ get_link_info (const struct nlmsghdr *message) attribute = RTA_NEXT (attribute, length); } - log_debug (LOG_NETLINK, "link flags: {:X}", ifa->ifa_flags); + log_debug (LOG_NETLINK, std::format ("link flags: {:X}", ifa->ifa_flags)); return ifa; error: @@ -1142,7 +1142,7 @@ print_ifla_name (int id) int i = 0; while (1) { if (iflas [i].value == -1 && iflas [i].name == 0) { - log_info_nocheck_fmt (LOG_NETLINK, "Unknown ifla->name: unknown id {}", id); + log_info_nocheck (LOG_NETLINK, std::format ("Unknown ifla->name: unknown id {}", id)); break; } @@ -1150,7 +1150,7 @@ print_ifla_name (int id) i++; continue; } - log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", optional_string (iflas [i].name), iflas [i].value); + log_info_nocheck (LOG_NETLINK, std::format ("ifla->name: {} ({})", iflas [i].name, iflas [i].value)); break; } } @@ -1165,7 +1165,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) char *msg, *tmp; if (!list) { - log_info_nocheck_fmt (LOG_NETLINK, "No list to print in {}", __FUNCTION__); + log_info_nocheck (LOG_NETLINK, std::format ("No list to print in {}", __FUNCTION__)); return; } @@ -1180,7 +1180,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) cur = cur->ifa_next; } - log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, optional_string (msg, "[no addresses]")); + log_info_nocheck (LOG_NETLINK, std::format ("{}: {}", title, msg ? msg : "[no addresses]"sv)); free (msg); } #endif diff --git a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh index 259a0d5c879..240223b396c 100644 --- a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh @@ -23,21 +23,21 @@ namespace xamarin::android { constexpr bool PREFER_AOT_CACHE = false; lib_handle = internal::MonodroidDl::monodroid_dlopen (library_name, MONO_DL_LOCAL, nullptr, PREFER_AOT_CACHE); if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", optional_string (library_name), optional_string (symbol_name)); + log_warn (LOG_ASSEMBLY, std::format ("Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name)); return nullptr; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", optional_string (library_name)); + log_debug (LOG_ASSEMBLY, std::format ("Library '{}' handle already cached by another thread", library_name)); } } } void *entry_handle = internal::MonodroidDl::monodroid_dlsym (lib_handle, symbol_name, nullptr, nullptr); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", optional_string (library_name), optional_string (symbol_name)); + log_warn (LOG_ASSEMBLY, std::format ("Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name)); return nullptr; } @@ -60,7 +60,7 @@ namespace xamarin::android { return nullptr; } - log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); + log_debug (LOG_ASSEMBLY, std::format ("Caching p/invoke entry {} @ {}", library_name, entrypoint_name)); (*api_map)[entrypoint_name] = entry_handle; return entry_handle; } @@ -81,7 +81,7 @@ namespace xamarin::android { ); if (already_loaded) { - log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); + log_debug (LOG_ASSEMBLY, std::format ("Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name)); } } @@ -147,7 +147,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", optional_string (library_name)); + log_warn (LOG_ASSEMBLY, std::format ("Internal error: null entry in p/invoke map for key '{}'", library_name)); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index 29ac736e433..269288a28c9 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -22,19 +22,18 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", - optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); + log_fatal (LOG_ASSEMBLY, std::format ("Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash)); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", optional_string (e.name), e.func, e.hash); + log_fatal (LOG_ASSEMBLY, std::format ("\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash)); } Helpers::abort_application ( LOG_ASSEMBLY, std::format ( "Failure handling a p/invoke request for '{}'@'{}'", - optional_string (entrypoint_name), - optional_string (library_name) + entrypoint_name, + library_name ) ); } @@ -77,8 +76,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha } // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below - log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", - optional_string (entrypoint_name), optional_string (library_name)); + log_debug (LOG_ASSEMBLY, std::format ("Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name)); } return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index 78d59b70bfa..d092be238cc 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -65,7 +65,7 @@ AndroidSystem::lookup_system_property (const char *name, size_t &value_len) noex return nullptr; if (application_config.system_property_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count); + log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count)); return nullptr; } @@ -138,7 +138,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 = Helpers::add_with_overflow_check (PROPERTY_VALUE_BUFFER_LEN, 1uz); - log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); + log_warn (LOG_DEFAULT, std::format ("Buffer to store system property may be too small, will copy only {} bytes", sp_value_len)); buf = new char [alloc_size]; } @@ -250,12 +250,12 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co } std::unique_ptr override_file {Util::path_combine (od, name)}; - log_info (LOG_DEFAULT, "Trying to get property from {}", override_file.get ()); + log_info (LOG_DEFAULT, std::format ("Trying to get property from {}", 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') { continue; } - log_info (LOG_DEFAULT, "Property '{}' from {} has value '{}'.", name, od, *value); + log_info (LOG_DEFAULT, std::format ("Property '{}' from {} has value '{}'.", name, od, *value)); return result; } #endif // def DEBUG @@ -281,7 +281,7 @@ AndroidSystem::create_update_dir (char *override_dir) noexcept override_dirs [0] = override_dir; Util::create_public_directory (override_dir); - log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); + log_warn (LOG_DEFAULT, std::format ("Creating public update directory: `{}`", override_dir)); } bool @@ -306,16 +306,16 @@ AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exis if (path == nullptr || *path == '\0') return nullptr; - log_info (LOG_ASSEMBLY, "Trying to load shared library '{}'", path); + log_info (LOG_ASSEMBLY, std::format ("Trying to load shared library '{}'", path)); if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { - log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); + log_info (LOG_ASSEMBLY, std::format ("Shared library '{}' not found", path)); return nullptr; } char *error = nullptr; void *handle = java_interop_lib_load (path, dl_flags, &error); if (handle == nullptr && Util::should_log (LOG_ASSEMBLY)) - log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '{}'. {}", path, error); + log_info_nocheck (LOG_ASSEMBLY, std::format ("Failed to load shared library '{}'. {}", path, error)); java_interop_free (error); return handle; } @@ -450,9 +450,9 @@ AndroidSystem::get_max_gref_count_from_system (void) noexcept if (max < 0) max = std::numeric_limits::max (); if (*e) { - log_warn (LOG_GC, "Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); + log_warn (LOG_GC, std::format ("Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ())); } - log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); + log_warn (LOG_GC, std::format ("Overriding max JNI Global Reference count to {}", max)); } return max; } @@ -478,7 +478,7 @@ AndroidSystem::setup_environment (const char *name, const char *value) noexcept if (isupper (name [0]) || name [0] == '_') { if (setenv (name, v, 1) < 0) - log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("(Debug) Failed to set environment variable: {}", strerror (errno))); return; } @@ -492,13 +492,13 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept struct stat sbuf; if (::stat (path, &sbuf) < 0) { - log_warn (LOG_DEFAULT, "Failed to stat the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to stat the environment override file {}: {}", path, strerror (errno))); return; } int fd = open (path, O_RDONLY); if (fd < 0) { - log_warn (LOG_DEFAULT, "Failed to open the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to open the environment override file {}: {}", path, strerror (errno))); return; } @@ -515,7 +515,7 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept } while (r < 0 && errno == EINTR); if (nread == 0) { - log_warn (LOG_DEFAULT, "Failed to read the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to read the environment override file {}: {}", path, strerror (errno))); return; } @@ -536,26 +536,26 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept // # Variable value, terminated with NUL and padded to [value width] with NUL characters // value\0 if (nread < OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) { - log_warn (LOG_DEFAULT, "Invalid format of the environment override file {}: malformatted header", path); + log_warn (LOG_DEFAULT, std::format ("Invalid format of the environment override file {}: malformatted header", path)); return; } char *endptr; unsigned long name_width = strtoul (buf.get (), &endptr, 16); if ((name_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path); + log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: name width has invalid format", path)); return; } unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path); + log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: value width has invalid format", path)); return; } uint64_t data_width = name_width + value_width; if (data_width > file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path); + log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: invalid data size", path)); return; } @@ -563,11 +563,11 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept char *name = buf.get () + OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE; while (data_size > 0 && data_size >= data_width) { if (*name == '\0') { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ()); + log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ())); return; } - log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width); + log_debug (LOG_DEFAULT, std::format ("Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width)); setup_environment (name, name + name_width); name += data_width; data_size -= data_width; @@ -602,10 +602,10 @@ AndroidSystem::setup_environment () noexcept } if (aotMode != MonoAotMode::MONO_AOT_MODE_LAST) { - log_debug (LOG_DEFAULT, "Mono AOT mode: {}", mono_aot_mode_name); + log_debug (LOG_DEFAULT, std::format ("Mono AOT mode: {}", mono_aot_mode_name)); } else { if (!is_interpreter_enabled ()) { - log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: {}", mono_aot_mode_name); + log_warn (LOG_DEFAULT, std::format ("Unknown Mono AOT mode: {}", mono_aot_mode_name)); } else { log_warn (LOG_DEFAULT, "Mono AOT mode: interpreter"sv); } @@ -613,7 +613,7 @@ AndroidSystem::setup_environment () noexcept } if (application_config.environment_variable_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count); + log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count)); return; } @@ -629,10 +629,10 @@ AndroidSystem::setup_environment () noexcept var_value = ""; #if defined (DEBUG) - log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); + log_info (LOG_DEFAULT, std::format ("Setting environment variable '{}' to '{}'", var_name, var_value)); #endif // def DEBUG if (setenv (var_name, var_value, 1) < 0) - log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to set environment variable: {}", strerror (errno))); } #if defined (DEBUG) log_debug (LOG_DEFAULT, "Loading environment from override directories."sv); @@ -641,9 +641,9 @@ AndroidSystem::setup_environment () noexcept continue; } std::unique_ptr env_override_file {Util::path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; - log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); + log_debug (LOG_DEFAULT, std::format ("{}", env_override_file.get ())); if (Util::file_exists (env_override_file.get ())) { - log_debug (LOG_DEFAULT, "Loading {}", env_override_file.get ()); + log_debug (LOG_DEFAULT, std::format ("Loading {}", env_override_file.get ())); setup_environment_from_override_file (env_override_file.get ()); } } @@ -671,12 +671,12 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep { // 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 {}", libmonodroid_path.get ()); + log_debug (LOG_ASSEMBLY, std::format ("Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ())); if (!Util::file_exists (libmonodroid_path.get ())) { - log_debug (LOG_ASSEMBLY, "{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); + log_debug (LOG_ASSEMBLY, std::format ("{} 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 {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, std::format ("Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); set_embedded_dso_mode_enabled (false); } } @@ -689,7 +689,7 @@ AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks 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: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, std::format ("Added filesystem DSO lookup location: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); } else { log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); @@ -725,7 +725,7 @@ AndroidSystem::add_apk_libdir (const char *apk, size_t &index, const char *abi) { 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: {}", app_lib_directories[index]); + log_debug (LOG_ASSEMBLY, std::format ("Added APK DSO lookup location: {}", app_lib_directories[index])); index++; } diff --git a/src/native/mono/runtime-base/monodroid-dl.hh b/src/native/mono/runtime-base/monodroid-dl.hh index 93cb8b70b48..621d0744fe7 100644 --- a/src/native/mono/runtime-base/monodroid-dl.hh +++ b/src/native/mono/runtime-base/monodroid-dl.hh @@ -48,11 +48,11 @@ namespace xamarin::android::internal size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); + log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in AOT cache", hash)); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); + log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in DSO cache", hash)); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } @@ -102,7 +102,7 @@ namespace xamarin::android::internal if (MonodroidState::is_startup_in_progress ()) { auto ignore_component = [&](const char *label, MonoComponent component) -> bool { if ((application_config.mono_components_mask & component) != component) { - log_info (LOG_ASSEMBLY, "Mono '{}' component requested but not packaged, ignoring", label); + log_info (LOG_ASSEMBLY, std::format ("Mono '{}' component requested but not packaged, ignoring", label)); return true; } @@ -150,7 +150,7 @@ namespace xamarin::android::internal } hash_t name_hash = xxhash::hash (name, strlen (name)); - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash); + log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash)); DSOCacheEntry *dso = nullptr; if (prefer_aot_cache) { @@ -167,7 +167,7 @@ namespace xamarin::android::internal dso = find_only_dso_cache_entry (name_hash); } - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name); + log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name)); if (dso == nullptr) { // DSO not known at build time, try to load it @@ -177,7 +177,7 @@ namespace xamarin::android::internal } if (dso->ignore) { - log_info (LOG_ASSEMBLY, "Request to load '{}' ignored, it is known not to exist", dso->name); + log_info (LOG_ASSEMBLY, std::format ("Request to load '{}' ignored, it is known not to exist", dso->name)); return nullptr; } From 55587b6fcdf9587b535cd1a1e8c98d7f423fba13 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 27 Nov 2024 20:51:12 +0100 Subject: [PATCH 017/143] More std::format --- .../common/include/runtime-base/strings.hh | 8 ++-- src/native/common/include/shared/log_level.hh | 1 - .../mono/monodroid/embedded-assemblies-zip.cc | 2 +- .../mono/monodroid/mono-image-loader.hh | 2 +- .../mono/monodroid/monodroid-glue-internal.hh | 2 +- .../mono/monodroid/monodroid-networkinfo.cc | 6 +-- .../mono/monodroid/monodroid-tracing.cc | 2 +- .../monodroid/xamarin-android-app-context.cc | 38 ++++++++++--------- .../mono/pinvoke-override/precompiled.cc | 3 +- .../mono/runtime-base/internal-pinvokes.hh | 1 + src/native/mono/runtime-base/logger.cc | 18 +++++---- .../mono/runtime-base/timing-internal.cc | 6 +-- .../mono/runtime-base/timing-internal.hh | 4 +- src/native/mono/runtime-base/timing.hh | 4 +- src/native/mono/runtime-base/util.cc | 8 ++-- src/native/mono/runtime-base/util.hh | 4 +- src/native/mono/shared/cpp-util.hh | 2 +- src/native/mono/shared/helpers.cc | 15 ++++---- src/native/mono/shared/log_functions.cc | 4 +- .../debug-app-helper.cc | 36 +++++++++--------- 20 files changed, 86 insertions(+), 80 deletions(-) diff --git a/src/native/common/include/runtime-base/strings.hh b/src/native/common/include/runtime-base/strings.hh index b076e4f5ca9..3b920e61919 100644 --- a/src/native/common/include/runtime-base/strings.hh +++ b/src/native/common/include/runtime-base/strings.hh @@ -205,7 +205,7 @@ namespace xamarin::android { } if (!can_access (start_index)) { - log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); + log_error (LOG_DEFAULT, std::format ("Cannot convert string to integer, index {} is out of range", start_index)); return false; } @@ -229,17 +229,17 @@ namespace xamarin::android { } if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); + log_error (LOG_DEFAULT, std::format ("Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max))); return false; } if (endp == s) { - log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); + log_error (LOG_DEFAULT, std::format ("Value {} does not represent a base {} integer", reinterpret_cast(s), base)); return false; } if (*endp != '\0') { - log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); + log_error (LOG_DEFAULT, std::format ("Value {} has non-numeric characters at the end", reinterpret_cast(s))); return false; } diff --git a/src/native/common/include/shared/log_level.hh b/src/native/common/include/shared/log_level.hh index e11dc18dae9..31a1b22dac0 100644 --- a/src/native/common/include/shared/log_level.hh +++ b/src/native/common/include/shared/log_level.hh @@ -126,4 +126,3 @@ static inline constexpr void log_fatal (LogCategories category, std::string_view } extern unsigned int log_categories; -#endif // ndef LOG_LEVEL_HH diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 59069330dfb..d195b26fcaf 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -45,7 +45,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vectorCallStaticObjectMethod (NetworkInterface_class, NetworkInterface_getByName, NetworkInterface_nameArg); env->DeleteLocalRef (NetworkInterface_nameArg); if (env->ExceptionOccurred ()) { - log_warn (LOG_NET, "Java exception occurred while looking up the interface '{}'", ifname); + log_warn (LOG_NET, std::format ("Java exception occurred while looking up the interface '{}'", ifname)); env->ExceptionDescribe (); env->ExceptionClear (); goto leave; } if (!networkInterface) { - log_warn (LOG_NET, "Failed to look up interface '{}' using Java API", ifname); + log_warn (LOG_NET, std::format ("Failed to look up interface '{}' using Java API", ifname)); ret = FALSE; goto leave; } @@ -118,7 +118,7 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo leave: if (!ret) - log_warn (LOG_NET, "Unable to determine interface '{}' state using Java API", ifname); + log_warn (LOG_NET, std::format ("Unable to determine interface '{}' state using Java API", ifname)); if (networkInterface != nullptr && env != nullptr) { env->DeleteLocalRef (networkInterface); diff --git a/src/native/mono/monodroid/monodroid-tracing.cc b/src/native/mono/monodroid/monodroid-tracing.cc index adb9f0db1d6..892a5938393 100644 --- a/src/native/mono/monodroid/monodroid-tracing.cc +++ b/src/native/mono/monodroid/monodroid-tracing.cc @@ -27,7 +27,7 @@ MonodroidRuntime::log_traces (JNIEnv *env, TraceKind kind, const char *first_lin char *err = nullptr; void *handle = MonodroidDl::monodroid_dlopen (SharedConstants::xamarin_native_tracing_name.data (), MONO_DL_EAGER, &err, nullptr); if (handle == nullptr) { - log_warn (LOG_DEFAULT, "Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err); + log_warn (LOG_DEFAULT, std::format ("Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err)); } else { load_symbol (handle, "xa_get_native_backtrace", _xa_get_native_backtrace); load_symbol (handle, "xa_get_managed_backtrace", _xa_get_managed_backtrace); diff --git a/src/native/mono/monodroid/xamarin-android-app-context.cc b/src/native/mono/monodroid/xamarin-android-app-context.cc index 9ef193ddeb7..e55635f2443 100644 --- a/src/native/mono/monodroid/xamarin-android-app-context.cc +++ b/src/native/mono/monodroid/xamarin-android-app-context.cc @@ -15,7 +15,7 @@ MonodroidRuntime::get_method_name (uint32_t mono_image_index, uint32_t method_to { uint64_t id = (static_cast(mono_image_index) << 32) | method_token; - log_debug (LOG_ASSEMBLY, "MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index); + log_debug (LOG_ASSEMBLY, std::format ("MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index)); size_t i = 0uz; while (mm_method_names[i].id != 0) { if (mm_method_names[i].id == id) { @@ -43,9 +43,10 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas { log_debug ( LOG_ASSEMBLY, - "MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", - optional_string (get_method_name (mono_image_index, method_token)), method_token, - optional_string (get_class_name (class_index)), class_index + std::format ("MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", + get_method_name (mono_image_index, method_token), method_token, + get_class_name (class_index), class_index + ) ); if (class_index >= marshal_methods_number_of_classes) [[unlikely]] { @@ -80,29 +81,32 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, - "Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", - optional_string (mono_method_full_name (method, true)), - ret, - mono_image_index, - class_index, - method_token + std::format ("Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", + mono_method_full_name (method, true), + ret, + mono_image_index, + class_index, + method_token + ) ); return; } log_fatal ( LOG_DEFAULT, - "Failed to obtain function pointer to method '{}' in class '{}'", - optional_string (get_method_name (mono_image_index, method_token)), - optional_string (get_class_name (class_index)) + std::format ("Failed to obtain function pointer to method '{}' in class '{}'", + get_method_name (mono_image_index, method_token), + get_class_name (class_index) + ) ); log_fatal ( LOG_DEFAULT, - "Looked for image index {}, class index {}, method token {:x}", - mono_image_index, - class_index, - method_token + std::format ("Looked for image index {}, class index {}, method token {:x}", + mono_image_index, + class_index, + method_token + ) ); if (image == nullptr) { diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index 269288a28c9..1ef4bbfaba0 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -67,8 +67,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", - optional_string (entrypoint_name), optional_string (library_name)); + log_fatal (LOG_ASSEMBLY, std::format ("Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name)); return nullptr; // let Mono deal with the fallout } diff --git a/src/native/mono/runtime-base/internal-pinvokes.hh b/src/native/mono/runtime-base/internal-pinvokes.hh index 200c7b97204..1fbfc4c1e01 100644 --- a/src/native/mono/runtime-base/internal-pinvokes.hh +++ b/src/native/mono/runtime-base/internal-pinvokes.hh @@ -3,6 +3,7 @@ #include #include +//#include #include #include diff --git a/src/native/mono/runtime-base/logger.cc b/src/native/mono/runtime-base/logger.cc index 256f6f2b030..f11c9aa52ad 100644 --- a/src/native/mono/runtime-base/logger.cc +++ b/src/native/mono/runtime-base/logger.cc @@ -29,11 +29,13 @@ namespace { if (path && access (path, W_OK) < 0) { log_warn (category, - "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", - optional_string (path), - strerror (errno), - optional_string (override_dir), - optional_string (filename) + std::format ( + "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", + path, + strerror (errno), + override_dir, + filename + ) ); path = NULL; } @@ -51,7 +53,7 @@ namespace { if (f) { Util::set_world_accessable (path); } else { - log_warn (category, "Could not open path '{}' for logging: {}", optional_string (path), strerror (errno)); + log_warn (category, std::format ("Could not open path '{}' for logging: {}", path, strerror (errno))); } free (p); @@ -77,12 +79,12 @@ Logger::set_debugger_log_level (const char *level) noexcept unsigned long v = strtoul (level, nullptr, 0); if (v == std::numeric_limits::max () && errno == ERANGE) { - log_error (LOG_DEFAULT, "Invalid debugger log level value '{}', expecting a positive integer or zero", level); + log_error (LOG_DEFAULT, std::format ("Invalid debugger log level value '{}', 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 {}, resetting to the maximum value.", std::numeric_limits::max ()); + log_warn (LOG_DEFAULT, std::format ("Debugger log level value is higher than the maximum of {}, resetting to the maximum value.", std::numeric_limits::max ())); v = std::numeric_limits::max (); } diff --git a/src/native/mono/runtime-base/timing-internal.cc b/src/native/mono/runtime-base/timing-internal.cc index 6efcfdae461..7b23705d880 100644 --- a/src/native/mono/runtime-base/timing-internal.cc +++ b/src/native/mono/runtime-base/timing-internal.cc @@ -78,11 +78,11 @@ FastTiming::dump () noexcept log_write (LOG_TIMING, LogLevel::Info, "[2/4] Accumulated performance results"); ns_to_time (total_assembly_load_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/5] Assembly load: {}:{}::{}", sec, ms, ns); + log_info_nocheck (LOG_TIMING, std::format (" [2/5] Assembly load: {}:{}::{}", sec, ms, ns)); ns_to_time (total_java_to_managed_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns); + log_info_nocheck (LOG_TIMING, std::format (" [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns)); ns_to_time (total_managed_to_java_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns); + log_info_nocheck (LOG_TIMING, std::format (" [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns)); } diff --git a/src/native/mono/runtime-base/timing-internal.hh b/src/native/mono/runtime-base/timing-internal.hh index 6389e719e7e..804e2544a9d 100644 --- a/src/native/mono/runtime-base/timing-internal.hh +++ b/src/native/mono/runtime-base/timing-internal.hh @@ -144,7 +144,7 @@ namespace xamarin::android::internal // likely we'll run out of memory way, way, way before that happens size_t old_size = events.capacity (); events.reserve (old_size << 1); - log_warn (LOG_TIMING, "Reallocated timing event buffer from {} to {}", old_size, events.size ()); + log_warn (LOG_TIMING, std::format ("Reallocated timing event buffer from {} to {}", old_size, events.size ())); } } @@ -246,7 +246,7 @@ namespace xamarin::android::internal [[gnu::always_inline]] bool is_valid_event_index (size_t index, const char *method_name) noexcept { if (index >= events.capacity ()) [[unlikely]] { - log_warn (LOG_TIMING, "Invalid event index passed to method '{}'", method_name); + log_warn (LOG_TIMING, std::format ("Invalid event index passed to method '{}'", method_name)); return false; } diff --git a/src/native/mono/runtime-base/timing.hh b/src/native/mono/runtime-base/timing.hh index 191ec55df2f..31f9892e918 100644 --- a/src/native/mono/runtime-base/timing.hh +++ b/src/native/mono/runtime-base/timing.hh @@ -93,14 +93,14 @@ namespace xamarin::android { timing_diff diff (period); - log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); + log_info_nocheck (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); } static void warn (timing_period const &period, const char *message) noexcept { timing_diff diff (period); - log_warn (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); + log_warn (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); } managed_timing_sequence* get_available_sequence () noexcept diff --git a/src/native/mono/runtime-base/util.cc b/src/native/mono/runtime-base/util.cc index d377cc46c31..388c9beb9c3 100644 --- a/src/native/mono/runtime-base/util.cc +++ b/src/native/mono/runtime-base/util.cc @@ -150,7 +150,7 @@ Util::create_public_directory (const char *dir) mode_t m = umask (0); int ret = mkdir (dir, 0777); if (ret < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", dir, std::strerror (errno))); } umask (m); } @@ -198,7 +198,7 @@ Util::set_world_accessable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); + log_error (LOG_DEFAULT, std::format ("chmod(\"{}\", 0664) failed: {}", path, strerror (errno))); } } @@ -211,7 +211,7 @@ Util::set_user_executable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\") failed: {}", path, strerror (errno)); + log_error (LOG_DEFAULT, std::format ("chmod(\"{}\") failed: {}", path, strerror (errno))); } } @@ -298,7 +298,7 @@ Util::monodroid_fopen (const char *filename, const char *mode) */ ret = fopen (filename, mode); if (ret == nullptr) { - log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); + log_error (LOG_DEFAULT, std::format ("fopen failed for file {}: {}", filename, strerror (errno))); return nullptr; } diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 3dbdeae10bc..2c553ff63a6 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -80,7 +80,7 @@ namespace xamarin::android { struct stat sbuf; if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, "Failed to stat file '{}': {}", file_name, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Failed to stat file '{}': {}", file_name, std::strerror (errno))); return std::nullopt; } @@ -91,7 +91,7 @@ namespace xamarin::android { int fd = openat (dirfd, file_name, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, "Failed to open file '{}' for reading: {}", file_name, std::strerror (errno)); + log_error (LOG_ASSEMBLY, std::format ("Failed to open file '{}' for reading: {}", file_name, std::strerror (errno))); return std::nullopt; } diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index f2f03b9d5b6..1c0e5cfd30e 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -86,7 +86,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l // 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: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); + log_info_nocheck (LOG_DEFAULT, std::format ("loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ())); } namespace xamarin::android diff --git a/src/native/mono/shared/helpers.cc b/src/native/mono/shared/helpers.cc index d1a785cc09b..645f30e0d84 100644 --- a/src/native/mono/shared/helpers.cc +++ b/src/native/mono/shared/helpers.cc @@ -2,7 +2,7 @@ #include #include -#include +#include "helpers.hh" #include "log_types.hh" using namespace xamarin::android; @@ -11,7 +11,7 @@ using namespace xamarin::android; Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept { // Log it, but also... - log_fatal (category, "{}", message); + log_fatal (category, std::string_view { message }); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -35,11 +35,12 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - "Abort at {}:{}:{} ('%s')", - file_name, - sloc.line (), - sloc.column (), - sloc.function_name () + std::format ("Abort at {}:{}:{} ('%s')", + file_name, + sloc.line (), + sloc.column (), + sloc.function_name () + ) ); } std::abort (); diff --git a/src/native/mono/shared/log_functions.cc b/src/native/mono/shared/log_functions.cc index 394ba2a1927..e82f2bd5856 100644 --- a/src/native/mono/shared/log_functions.cc +++ b/src/native/mono/shared/log_functions.cc @@ -3,8 +3,8 @@ #include -#include "java-interop-logger.h" -#include +//#include "java-interop-logger.h" +#include "log_types.hh" // Must match the same ordering as LogCategories static constexpr std::array log_names = { diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index 85de1c000ed..711317c7a08 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -13,7 +13,7 @@ #include "util.hh" #include "debug-app-helper.hh" #include "shared-constants.hh" -#include +#include "jni-wrappers.hh" #include "log_types.hh" using namespace xamarin::android; @@ -48,7 +48,7 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); + log_warn (LOG_DEFAULT, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); } const char *monosgen_path = get_libmonosgen_path (); @@ -74,10 +74,10 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) break; log_warn (LOG_DEFAULT, - "Copying file `{}` from external location `{}` to internal location `{}`", - optional_string (file), - optional_string (from_dir), - optional_string (to_dir) + std::format ( + "Copying file `{}` from external location `{}` to internal location `{}`", + file, from_dir, to_dir + ) ); to_file = Util::path_combine (to_dir, file); @@ -86,12 +86,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) int r = unlink (to_file); if (r < 0 && errno != ENOENT) { - log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", optional_string (to_file), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Unable to delete file `{}`: {}", to_file, strerror (errno))); break; } if (!Util::file_copy (to_file, from_file)) { - log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", optional_string (from_file), optional_string (to_file), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno))); break; } @@ -110,22 +110,22 @@ copy_native_libraries_to_internal_location () dirent *e; char *dir_path = Util::path_combine (od, "lib"); - log_warn (LOG_DEFAULT, "checking directory: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, std::format ("checking directory: `{}`", dir_path)); if (dir_path == nullptr || !Util::directory_exists (dir_path)) { - log_warn (LOG_DEFAULT, "directory does not exist: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, std::format ("directory does not exist: `{}`", dir_path)); delete[] dir_path; continue; } if ((dir = ::opendir (dir_path)) == nullptr) { - log_warn (LOG_DEFAULT, "could not open directory: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, std::format ("could not open directory: `{}`", dir_path)); delete[] dir_path; continue; } while ((e = readdir (dir)) != nullptr) { - log_warn (LOG_DEFAULT, "checking file: `{}`", optional_string (e->d_name)); + log_warn (LOG_DEFAULT, std::format ("checking file: `{}`", 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); } @@ -142,9 +142,9 @@ runtime_exists (const char *dir, char*& libmonoso) return false; libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); - log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", optional_string (libmonoso)); + log_warn (LOG_DEFAULT, std::format ("Checking whether Mono runtime exists at: {}", libmonoso)); if (Util::file_exists (libmonoso)) { - log_info (LOG_DEFAULT, "Mono runtime found at: {}", optional_string (libmonoso)); + log_info (LOG_DEFAULT, std::format ("Mono runtime found at: {}", libmonoso)); return true; } delete[] libmonoso; @@ -196,25 +196,25 @@ get_libmonosgen_path () if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { - log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", optional_string (link), optional_string (libmonoso)); + log_warn (LOG_DEFAULT, std::format ("symlink exists, recreating: {} -> {}", link, libmonoso)); unlink (link); result = symlink (libmonoso, link); } if (result != 0) - log_warn (LOG_DEFAULT, "symlink failed with errno={} {}", errno, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("symlink failed with errno={} {}", errno, strerror (errno))); } delete[] libmonoso; libmonoso = link; } - log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", optional_string (libmonoso)); + log_warn (LOG_DEFAULT, std::format ("Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv)); if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; if (runtime_exists (AndroidSystem::SYSTEM_LIB_PATH.data (), libmonoso)) return libmonoso; - log_fatal (LOG_DEFAULT, "Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO); + log_fatal (LOG_DEFAULT, std::format ("Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO)); for (const char *od : AndroidSystem::override_dirs) { if (od == nullptr) From 793eecfe7e3c1fde5cc22d14d154f47526808426 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 28 Nov 2024 17:17:26 +0100 Subject: [PATCH 018/143] Friendlier, no need to use `std::format` directly in log_* anymore --- .../common/include/runtime-base/strings.hh | 8 +- src/native/common/include/shared/log_level.hh | 94 ++++------ src/native/mono/monodroid/debug.cc | 61 +++---- .../mono/monodroid/embedded-assemblies-zip.cc | 69 ++++--- .../mono/monodroid/embedded-assemblies.cc | 171 +++++++++--------- .../mono/monodroid/embedded-assemblies.hh | 6 +- .../mono/monodroid/monodroid-glue-internal.hh | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 71 ++++---- .../mono/monodroid/monodroid-networkinfo.cc | 6 +- .../mono/monodroid/monodroid-tracing.cc | 2 +- src/native/mono/monodroid/osbridge.cc | 160 ++++++++-------- .../monodroid/xamarin-android-app-context.cc | 38 ++-- .../mono/monodroid/xamarin_getifaddrs.cc | 56 +++--- .../pinvoke-override-api-impl.hh | 12 +- .../mono/pinvoke-override/precompiled.cc | 8 +- .../mono/runtime-base/android-system.cc | 64 +++---- src/native/mono/runtime-base/logger.cc | 4 +- src/native/mono/runtime-base/monodroid-dl.hh | 12 +- .../mono/runtime-base/timing-internal.cc | 6 +- .../mono/runtime-base/timing-internal.hh | 4 +- src/native/mono/runtime-base/timing.hh | 4 +- src/native/mono/runtime-base/util.cc | 8 +- src/native/mono/runtime-base/util.hh | 4 +- src/native/mono/shared/cpp-util.hh | 2 +- src/native/mono/shared/helpers.cc | 13 +- src/native/mono/shared/log_functions.cc | 4 +- src/native/mono/shared/log_level.hh | 26 +++ .../debug-app-helper.cc | 32 ++-- 28 files changed, 459 insertions(+), 488 deletions(-) create mode 100644 src/native/mono/shared/log_level.hh diff --git a/src/native/common/include/runtime-base/strings.hh b/src/native/common/include/runtime-base/strings.hh index 3b920e61919..b076e4f5ca9 100644 --- a/src/native/common/include/runtime-base/strings.hh +++ b/src/native/common/include/runtime-base/strings.hh @@ -205,7 +205,7 @@ namespace xamarin::android { } if (!can_access (start_index)) { - log_error (LOG_DEFAULT, std::format ("Cannot convert string to integer, index {} is out of range", start_index)); + log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); return false; } @@ -229,17 +229,17 @@ namespace xamarin::android { } if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, std::format ("Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max))); + log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); return false; } if (endp == s) { - log_error (LOG_DEFAULT, std::format ("Value {} does not represent a base {} integer", reinterpret_cast(s), base)); + log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); return false; } if (*endp != '\0') { - log_error (LOG_DEFAULT, std::format ("Value {} has non-numeric characters at the end", reinterpret_cast(s))); + log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); return false; } diff --git a/src/native/common/include/shared/log_level.hh b/src/native/common/include/shared/log_level.hh index 31a1b22dac0..66b1cae5097 100644 --- a/src/native/common/include/shared/log_level.hh +++ b/src/native/common/include/shared/log_level.hh @@ -6,6 +6,7 @@ #include #include "java-interop-logger.h" +#include "log_level.hh" // We redeclare macros here #if defined(log_debug) @@ -16,59 +17,42 @@ #undef log_info #endif -#define DO_LOG_FMT(_level, _category_, _message_) \ +#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ do { \ if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck ((_category_), _message_); \ + ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ } \ } while (0) -#define log_debug(_category_, _message_) DO_LOG_FMT (debug, (_category_), (_message_)) -#define log_info(_category_, _message_) DO_LOG_FMT (info, (_category_), (_message_)) +// +// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec +// -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 - }; +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +namespace xamarin::android { // 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; } -// -// This will be enabled once all log_* calls are converted to std::format format -// -// template [[gnu::always_inline]] -// static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) -// { -// if (detail::_category_is_enabled (category)) { - -// log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); -// } -// } - -[[gnu::always_inline]] -static inline constexpr void log_debug_nocheck (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) { - log_write (category, xamarin::android::LogLevel::Debug, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] @@ -77,10 +61,10 @@ static inline constexpr void log_debug_nocheck (LogCategories category, std::str log_write (category, xamarin::android::LogLevel::Debug, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) { - log_write (category, xamarin::android::LogLevel::Info, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] @@ -89,38 +73,38 @@ static inline constexpr void log_info_nocheck (LogCategories category, std::stri log_write (category, xamarin::android::LogLevel::Info, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept { - log_write (category, xamarin::android::LogLevel::Warn, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] -static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept { log_write (category, xamarin::android::LogLevel::Warn, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept { - log_write (category, xamarin::android::LogLevel::Error, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] -static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept { log_write (category, xamarin::android::LogLevel::Error, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept { - log_write (category, xamarin::android::LogLevel::Fatal, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] -static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept { log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); } diff --git a/src/native/mono/monodroid/debug.cc b/src/native/mono/monodroid/debug.cc index 18d355bfa84..e72b7aa19a6 100644 --- a/src/native/mono/monodroid/debug.cc +++ b/src/native/mono/monodroid/debug.cc @@ -95,10 +95,9 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (!found) log_warn (LOG_DEFAULT, - std::format ("The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", - mname.get (), - libname.get () - ) + "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", + mname.get (), + libname.get () ); } @@ -110,7 +109,7 @@ bool Debug::load_profiler (void *handle, const char *desc, const char *symbol) { ProfilerInitializer func = reinterpret_cast (java_interop_lib_symbol (handle, symbol, nullptr)); - log_warn (LOG_DEFAULT, std::format ("Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func))); + log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func)); if (func != nullptr) { func (desc); @@ -140,7 +139,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, std::format ("Connection options: '{}'", options)); + log_info (LOG_DEFAULT, "Connection options: '{}'", options); args = Util::monodroid_strsplit (options, ",", 0); @@ -150,12 +149,12 @@ Debug::parse_options (char *options, ConnOptions *opts) if (strstr (arg, "port=") == arg) { int port = atoi (arg + strlen ("port=")); if (port < 0 || port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, std::format ("Invalid debug port value {}", port)); + log_error (LOG_DEFAULT, "Invalid debug port value {}", port); continue; } conn_port = static_cast(port); - log_info (LOG_DEFAULT, std::format ("XS port = {}", conn_port)); + log_info (LOG_DEFAULT, "XS port = {}", conn_port); } else if (strstr (arg, "timeout=") == arg) { char *endp; @@ -164,7 +163,7 @@ Debug::parse_options (char *options, ConnOptions *opts) if ((endp == arg) || (*endp != '\0')) log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, std::format ("Unknown connection option: '{}'", arg)); + log_info (LOG_DEFAULT, "Unknown connection option: '{}'", arg); } } } @@ -188,7 +187,7 @@ Debug::start_connection (char *options) cur_time = time (nullptr); if (opts.timeout_time && cur_time > opts.timeout_time) { - log_warn (LOG_DEBUGGER, std::format ("Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time)); + log_warn (LOG_DEBUGGER, "Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time); return DebuggerConnectionStatus::Unconnected; } @@ -199,7 +198,7 @@ Debug::start_connection (char *options) res = pthread_create (&conn_thread_id, nullptr, xamarin::android::conn_thread, this); if (res) { - log_error (LOG_DEFAULT, std::format ("Failed to create connection thread: {}", strerror (errno))); + log_error (LOG_DEFAULT, "Failed to create connection thread: {}", strerror (errno)); return DebuggerConnectionStatus::Error; } @@ -263,20 +262,20 @@ Debug::process_connection (int fd) return false; } if (rv <= 0) { - log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); + log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); return false; } rv = Util::recv_uninterrupted (fd, command, cmd_len); if (rv <= 0) { - log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); + log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); return false; } // null-terminate command [cmd_len] = 0; - log_info (LOG_DEFAULT, std::format ("Received cmd: '{}'.", command)); + log_info (LOG_DEFAULT, "Received cmd: '{}'.", command); if (process_cmd (fd, command)) return true; @@ -288,14 +287,14 @@ Debug::handle_server_connection (void) { int listen_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_socket == -1) { - log_info (LOG_DEFAULT, std::format ("Could not create socket for XS to connect to: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Could not create socket for XS to connect to: {}", strerror (errno)); return 1; } int flags = 1; int rv = setsockopt (listen_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); if (rv == -1 && Util::should_log (LOG_DEFAULT)) { - log_info_nocheck (LOG_DEFAULT, std::format ("Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno))); + log_info_nocheck_fmt (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno)); // not a fatal failure } @@ -309,7 +308,7 @@ Debug::handle_server_connection (void) listen_addr.sin_addr.s_addr = INADDR_ANY; rv = bind (listen_socket, (struct sockaddr *) &listen_addr, sizeof (listen_addr)); if (rv == -1) { - log_info (LOG_DEFAULT, std::format ("Could not bind to address: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Could not bind to address: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -321,7 +320,7 @@ Debug::handle_server_connection (void) rv = listen (listen_socket, 1); if (rv == -1) { - log_info (LOG_DEFAULT, std::format ("Could not listen for XS: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Could not listen for XS: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -371,7 +370,7 @@ Debug::handle_server_connection (void) } while (rv == -1 && errno == EINTR); if (rv == -1) { - log_info (LOG_DEFAULT, std::format ("Failed while waiting for XS to connect: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -379,18 +378,18 @@ Debug::handle_server_connection (void) socklen_t len = sizeof (struct sockaddr_in); int fd = accept (listen_socket, (struct sockaddr *) &listen_addr, &len); if (fd == -1) { - log_info (LOG_DEFAULT, std::format ("Failed to accept connection from XS: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Failed to accept connection from XS: {}", strerror (errno)); rv = 3; goto cleanup; } flags = 1; if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flags, sizeof (flags)) < 0) { - log_info (LOG_DEFAULT, std::format ("Could not set TCP_NODELAY on socket ({})", strerror (errno))); + log_info (LOG_DEFAULT, "Could not set TCP_NODELAY on socket ({})", strerror (errno)); // not a fatal failure } - log_info (LOG_DEFAULT, std::format ("Successfully received connection from XS on port {}, fd: {}", listen_port, fd)); + log_info (LOG_DEFAULT, "Successfully received connection from XS on port {}, fd: {}", listen_port, fd); need_new_conn = process_connection (fd); } @@ -442,7 +441,7 @@ Debug::process_cmd (int fd, char *cmd) constexpr std::string_view PONG_REPLY { "pong" }; if (strcmp (cmd, PING_CMD.data ()) == 0) { if (!Util::send_uninterrupted (fd, const_cast (reinterpret_cast (PONG_REPLY.data ())), 5)) - log_error (LOG_DEFAULT, std::format ("Got keepalive request from XS, but could not send response back ({})", strerror (errno))); + log_error (LOG_DEFAULT, "Got keepalive request from XS, but could not send response back ({})", strerror (errno)); return false; } @@ -488,7 +487,7 @@ Debug::process_cmd (int fd, char *cmd) profiler_fd = fd; profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { - log_error (LOG_DEFAULT, std::format ("Unknown profiler: '{}'", prof)); + log_error (LOG_DEFAULT, "Unknown profiler: '{}'", prof); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -497,7 +496,7 @@ Debug::process_cmd (int fd, char *cmd) pthread_mutex_unlock (&process_cmd_mutex); return use_fd; } else { - log_error (LOG_DEFAULT, std::format ("Unsupported command: '{}'", cmd)); + log_error (LOG_DEFAULT, "Unsupported command: '{}'", cmd); } return false; @@ -527,7 +526,7 @@ Debug::start_debugging (void) // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); if (enable_soft_breakpoints ()) { constexpr std::string_view soft_breakpoints { "--soft-breakpoints" }; @@ -554,7 +553,7 @@ Debug::start_profiling () if (!profiler_description) return; - log_info (LOG_DEFAULT, std::format ("Loading profiler: '{}'", profiler_description)); + log_info (LOG_DEFAULT, "Loading profiler: '{}'", profiler_description); monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), profiler_description, nullptr); } @@ -574,7 +573,7 @@ Debug::enable_soft_breakpoints (void) uname (&name); for (const char** ptr = soft_breakpoint_kernel_list; *ptr; ptr++) { if (strcmp (name.release, *ptr) == 0) { - log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled due to kernel version match ({})", name.release)); + log_info (LOG_DEBUGGER, "soft breakpoints enabled due to kernel version match ({})", name.release); return 1; } } @@ -582,17 +581,17 @@ Debug::enable_soft_breakpoints (void) char *value; /* Soft breakpoints are enabled by default */ if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS, &value) <= 0) { - log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled by default ({} property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ())); + log_info (LOG_DEBUGGER, "soft breakpoints enabled by default ({} property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); return 1; } bool ret; if (strcmp ("0", value) == 0) { ret = false; - log_info (LOG_DEBUGGER, std::format ("soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); + log_info (LOG_DEBUGGER, "soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); } else { ret = true; - log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); + log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); } delete[] value; return ret; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index d195b26fcaf..e0cf5548a5d 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -22,7 +22,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector } auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (assembly_store_map, entry_name.get ()); - log_debug (LOG_ASSEMBLY, std::format ("Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size)); + log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); auto header = static_cast(payload_start); if (header->magic != ASSEMBLY_STORE_MAGIC) { @@ -264,7 +262,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& dynamic_local_string entry_name; bool assembly_store_found = false; - log_debug (LOG_ASSEMBLY, std::format ("Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ())); + log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -300,14 +298,12 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& log_debug ( LOG_ASSEMBLY, - std::format ( - "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", - entry_name.get (), - number_of_zip_dso_entries, - name, - apk_entry->name_hash, - apk_entry->offset - ) + "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", + entry_name.get (), + number_of_zip_dso_entries, + name, + apk_entry->name_hash, + apk_entry->offset ); number_of_zip_dso_entries++; } @@ -331,9 +327,9 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ); } #ifdef DEBUG - log_info (LOG_ASSEMBLY, std::format ("Central directory offset: {}", cd_offset)); - log_info (LOG_ASSEMBLY, std::format ("Central directory size: {}", cd_size)); - log_info (LOG_ASSEMBLY, std::format ("Central directory entries: {}", cd_entries)); + log_info (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); + log_info (LOG_ASSEMBLY, "Central directory size: {}", cd_size); + log_info (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); #endif off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); if (retval < 0) { @@ -411,9 +407,8 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, - std::format ("Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", - entry.file_name, entry.name, entry.data_size - ) + "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", + entry.file_name, entry.name, entry.data_size ); } @@ -435,14 +430,14 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ // The simplest case - no file comment off_t ret = ::lseek (fd, -ZIP_EOCD_LEN, SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); + log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); return false; } std::array eocd; ssize_t nread = ::read (fd, eocd.data (), eocd.size ()); if (nread < 0 || nread != eocd.size ()) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); + log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); return false; } @@ -462,7 +457,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed ret = ::lseek (fd, static_cast(-alloc_size), SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); + log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); return false; } @@ -471,7 +466,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ nread = ::read (fd, buf.data (), buf.size ()); if (nread < 0 || static_cast(nread) != alloc_size) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); + log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); return false; } @@ -505,10 +500,8 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no if (result < 0) { log_error ( LOG_ASSEMBLY, - std::format ( - "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", - state.local_header_offset, std::strerror (errno), result, errno - ) + "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", + state.local_header_offset, std::strerror (errno), result, errno ); return false; } @@ -518,32 +511,32 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); if (nread < 0 || nread != ZIP_LOCAL_LEN) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno)); + log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); return false; } size_t index = 0; if (!zip_read_field (local_header, index, signature)) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header entry signature at offset {}", state.local_header_offset)); + log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); return false; } if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, std::format ("Invalid Local Header entry signature at offset {}", state.local_header_offset)); + log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); return false; } uint16_t file_name_length; index = LH_FILE_NAME_LENGTH_OFFSET; if (!zip_read_field (local_header, index, file_name_length)) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index))); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); return false; } uint16_t extra_field_length; index = LH_EXTRA_LENGTH_OFFSET; if (!zip_read_field (local_header, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index))); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); return false; } @@ -585,7 +578,7 @@ force_inline bool EmbeddedAssemblies::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { - log_error (LOG_ASSEMBLY, std::format ("Buffer too short to read {} bytes of data", to_read)); + log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); return false; } diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 2e7580dd398..269bf682783 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -130,7 +130,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb ) ); } else { - log_debug (LOG_ASSEMBLY, std::format ("Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name)); + log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -228,7 +228,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, std::format ("Assembly {} already mmapped by another thread, unmapping our copy", file.name)); + log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", file.name); munmap (map_info.area, file.data_size); map_info.area = nullptr; } @@ -243,18 +243,16 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc header[j] = isprint (p [j]) ? p [j] : '.'; header [header.size () - 1] = '\0'; - log_info_nocheck ( + log_info_nocheck_fmt ( LOG_ASSEMBLY, - std::format ( - "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", - file.data_offset, - static_cast(file.data), - pointer_add (file.data, file.data_size), - file.data_size, - file.name, - file.name, - header.data () - ) + "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", + file.data_offset, + static_cast(file.data), + pointer_add (file.data, file.data_size), + file.data_size, + file.name, + file.name, + header.data () ); } } @@ -289,7 +287,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (strcmp (assembly.name, abi_name.get ()) != 0) { return nullptr; } else { - log_debug (LOG_ASSEMBLY, std::format ("open_from_bundles: found architecture-specific: '{}'", abi_name.get ())); + log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", abi_name.get ()); } } @@ -350,7 +348,7 @@ EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_strin name.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, std::format ("individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ())); + log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ()); dynamic_local_string abi_name; abi_name @@ -397,7 +395,7 @@ template EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { hash_t name_hash = xxhash::hash (name.get (), name.length ()); - log_debug (LOG_ASSEMBLY, std::format ("assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash)); + log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash); const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) { @@ -430,16 +428,15 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string(assembly_runtime_info.image_data), - static_cast(assembly_runtime_info.debug_info_data), - static_cast(assembly_runtime_info.config_data), - static_cast(assembly_runtime_info.descriptor), - assembly_runtime_info.descriptor->data_size, - assembly_runtime_info.descriptor->debug_data_size, - assembly_runtime_info.descriptor->config_data_size, - name.get () - ) + "Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'", + static_cast(assembly_runtime_info.image_data), + static_cast(assembly_runtime_info.debug_info_data), + static_cast(assembly_runtime_info.config_data), + static_cast(assembly_runtime_info.descriptor), + assembly_runtime_info.descriptor->data_size, + assembly_runtime_info.descriptor->debug_data_size, + assembly_runtime_info.descriptor->config_data_size, + name.get () ); } @@ -554,7 +551,7 @@ EmbeddedAssemblies::binary_search (const Key *key, const Entry *base, size_t nme if constexpr (use_precalculated_size) { size = precalculated_size; - log_info (LOG_ASSEMBLY, std::format ("Pre-calculated entry size = {}", size)); + log_info (LOG_ASSEMBLY, "Pre-calculated entry size = {}", size); } while (nmemb > 0) { @@ -623,26 +620,26 @@ EmbeddedAssemblies::typemap_java_to_managed ([[maybe_unused]] hash_t hash, const entry = binary_search (java_type_name.get (), type_map.java_to_managed, type_map.entry_count); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ())); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ()); return nullptr; } const char *managed_type_name = entry->to; if (managed_type_name == nullptr) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ())); + log_debug (LOG_ASSEMBLY, "typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ()); return nullptr; } - log_debug (LOG_DEFAULT, std::format ("typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), managed_type_name)); + log_debug (LOG_DEFAULT, "typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), managed_type_name); MonoType *type = mono_reflection_type_from_name (const_cast(managed_type_name), nullptr); if (type == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, std::format ("typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ())); + log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ()); return nullptr; } MonoReflectionType *ret = mono_type_get_object (Util::get_current_domain (), type); if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type '{}'", managed_type_name)); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '{}'", managed_type_name); return nullptr; } @@ -662,16 +659,16 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java TypeMapModule *module = java_entry != nullptr && java_entry->module_index < map_module_count ? &map_modules[java_entry->module_index] : nullptr; if (module == nullptr) { if (java_entry == nullptr) { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash)); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash); } else { - log_warn (LOG_ASSEMBLY, std::format ("typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index)); + log_warn (LOG_ASSEMBLY, "typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index); } return nullptr; } const TypeMapModuleEntry *entry = binary_search (java_entry->type_token_id, module->map, module->entry_count); if (entry == nullptr) { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ())); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ()); return nullptr; } @@ -679,7 +676,7 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java module->image = mono_image_loaded (module->assembly_name); if (module->image == nullptr) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name)); + log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name); // Fake a request from MonoVM to load the assembly. MonoAssemblyName *assembly_name = mono_assembly_name_new (module->assembly_name); @@ -702,15 +699,15 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (module->image == nullptr) { - log_error (LOG_ASSEMBLY, std::format ("typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ())); + log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ()); return nullptr; } } - log_debug (LOG_ASSEMBLY, std::format ("typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id)); + log_debug (LOG_ASSEMBLY, "typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); MonoClass *klass = mono_class_get (module->image, java_entry->type_token_id); if (klass == nullptr) [[unlikely]] { - log_error (LOG_ASSEMBLY, std::format ("typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); + log_error (LOG_ASSEMBLY, "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); return nullptr; } @@ -721,7 +718,7 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java MonoReflectionType *ret = mono_type_get_object (domain, mono_class_get_type (klass)); if (ret == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); return nullptr; } @@ -786,7 +783,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapEntry *entry = typemap_managed_to_java (full_name.get ()); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ())); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ()); return nullptr; } @@ -807,13 +804,13 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo if (mvid == nullptr) { log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); } else { - log_info (LOG_ASSEMBLY, std::format ("typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ())); + log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ()); } return nullptr; } uint32_t token = mono_class_get_type_token (klass); - log_debug (LOG_ASSEMBLY, std::format ("typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF)); + log_debug (LOG_ASSEMBLY, "typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF); // Each map entry is a pair of 32-bit integers: [TypeTokenID][JavaMapArrayIndex] const TypeMapModuleEntry *entry = match->map != nullptr ? binary_search (token, match->map, match->entry_count) : nullptr; if (entry == nullptr) { @@ -823,41 +820,40 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo } if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token)); + log_debug (LOG_ASSEMBLY, "typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token); entry = binary_search (token, match->duplicate_map, match->duplicate_count); } if (entry == nullptr) { - log_info (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name)); + log_info (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name); return nullptr; } } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index)); + log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index); return nullptr; } TypeMapJava const& java_entry = map_java[entry->java_map_index]; if (java_entry.java_name_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index)); + log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index); return nullptr; } const char *ret = java_type_names[java_entry.java_name_index]; if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: empty Java type name returned for entry at index {}", entry->java_map_index)); + log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}", entry->java_map_index); } log_debug ( LOG_ASSEMBLY, - std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", - token, - token, - MonoGuidString (mvid).get (), - match->assembly_name, - ret - ) + "typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", + token, + token, + MonoGuidString (mvid).get (), + match->assembly_name, + ret ); return ret; @@ -919,7 +915,7 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons log_info ( LOG_ASSEMBLY, - std::format (" mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", mmap_info.area, pointer_add (mmap_info.area, mmap_info.size), mmap_info.size, @@ -928,7 +924,6 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons file_info.size, fd, filename - ) ); return file_info; @@ -948,7 +943,7 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro ) ); } - log_debug (LOG_ASSEMBLY, std::format ("APK {} FD: {}", apk, fd)); + log_debug (LOG_ASSEMBLY, "APK {} FD: {}", apk, fd); zip_load_entries (fd, apk, should_register); } @@ -975,40 +970,40 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char struct stat sbuf; int res = fstatat (dir_fd, file_path, &sbuf, 0); if (res < 0) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); return false; } file_size = static_cast(sbuf.st_size); if (file_size < sizeof (header)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header))); + log_error (LOG_ASSEMBLY, "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header)); return false; } fd = openat (dir_fd, file_path, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno)); return false; } ssize_t nread = do_read (fd, &header, sizeof (header)); if (nread <= 0) { if (nread < 0) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); } else { - log_error (LOG_ASSEMBLY, std::format ("typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path)); + log_error (LOG_ASSEMBLY, "typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path); } return false; } if (header.magic != expected_magic) { - log_error (LOG_ASSEMBLY, std::format ("typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic)); + log_error (LOG_ASSEMBLY, "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic); return false; } if (header.version != MODULE_FORMAT_VERSION) { - log_error (LOG_ASSEMBLY, std::format ("typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version)); + log_error (LOG_ASSEMBLY, "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version); return false; } @@ -1021,14 +1016,14 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ size_t entry_size = header.module_file_name_width; size_t data_size = entry_size * type_map_count; if (sizeof(header) + data_size > file_size) { - log_error (LOG_ASSEMBLY, std::format ("typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size)); + log_error (LOG_ASSEMBLY, "typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size); return nullptr; } auto data = std::make_unique (data_size); ssize_t nread = do_read (index_fd, data.get (), data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno)); return nullptr; } @@ -1044,7 +1039,7 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ std::unique_ptr EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap index file '{}/{}'", dir_path, index_path)); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", dir_path, index_path); TypeMapIndexHeader header; size_t file_size; @@ -1071,7 +1066,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * ssize_t nread = do_read (file_fd, module.assembly_name, header.assembly_name_length); if (nread != static_cast(header.assembly_name_length)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno)); return false; } @@ -1080,16 +1075,14 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, - std::format ( - "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", - dir_path, - file_path, - header.entry_count, - header.java_name_width, - header.managed_name_width, - header.assembly_name_length, - module.assembly_name - ) + "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", + dir_path, + file_path, + header.entry_count, + header.java_name_width, + header.managed_name_width, + header.assembly_name_length, + module.assembly_name ); // [name][index] @@ -1103,7 +1096,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * module.data = new uint8_t [data_size]; nread = do_read (file_fd, module.data, data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno)); return false; } @@ -1147,7 +1140,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * bool EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMap &module) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap file '{}/{}'", dir_path, file_path)); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", dir_path, file_path); bool ret = true; BinaryTypeMapHeader header; @@ -1186,7 +1179,7 @@ EmbeddedAssemblies::register_from_apk (const char *apk_file, monodroid_should_re gather_bundled_assemblies_from_apk (apk_file, should_register); - log_info (LOG_ASSEMBLY, std::format ("Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev)); + log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev); return number_of_found_assemblies; } @@ -1290,10 +1283,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( [[gnu::always_inline]] size_t EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look_for_mangled_names, monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, std::format ("Looking for assemblies in '{}'", lib_dir_path)); + log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", lib_dir_path); DIR *lib_dir = opendir (lib_dir_path); // TODO: put it in a scope guard at some point if (lib_dir == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno)); return 0; } @@ -1302,14 +1295,14 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno)); closedir (lib_dir); return 0; } state.file_fd = dup (dir_fd); if (state.file_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno)); closedir (lib_dir); return 0; } @@ -1326,7 +1319,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno)); continue; // keep going, no harm } break; // No more entries, we're done @@ -1346,7 +1339,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look // ...and we can handle the runtime config entry if (!runtime_config_blob_found && std::strncmp (cur->d_name, SharedConstants::RUNTIME_CONFIG_BLOB_NAME.data (), SharedConstants::RUNTIME_CONFIG_BLOB_NAME.size ()) == 0) { - log_debug (LOG_ASSEMBLY, std::format ("Mapping runtime config blob from '{}'", cur->d_name)); + log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", cur->d_name); auto file_size = Util::get_file_size_at (state.file_fd, cur->d_name); if (!file_size) { continue; @@ -1393,6 +1386,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, std::format ("Found {} assemblies on the filesystem", assembly_count)); + log_debug (LOG_ASSEMBLY, "Found {} assemblies on the filesystem", assembly_count); return assembly_count; } diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index fe7493506fa..a505721bf23 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -310,7 +310,7 @@ namespace xamarin::android::internal { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, std::format ("Not an ELF image: {}", file_name)); + log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", file_name); // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } @@ -329,7 +329,7 @@ namespace xamarin::android::internal { static void store_mapped_runtime_config_data (md_mmap_info const& map_info, const char *file_name) noexcept { auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (map_info, file_name); - log_debug (LOG_ASSEMBLY, std::format ("Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size)); + log_debug (LOG_ASSEMBLY, "Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size); runtime_config_data = payload_start; runtime_config_data_size = payload_size; runtime_config_blob_found = true; @@ -436,7 +436,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, std::format ("Unmangled name to '{}'", name.get ())); + log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", name.get ()); }; private: diff --git a/src/native/mono/monodroid/monodroid-glue-internal.hh b/src/native/mono/monodroid/monodroid-glue-internal.hh index 8a1e76bf425..2708ac58205 100644 --- a/src/native/mono/monodroid/monodroid-glue-internal.hh +++ b/src/native/mono/monodroid/monodroid-glue-internal.hh @@ -128,7 +128,7 @@ namespace xamarin::android::internal void *symptr = MonodroidDl::monodroid_dlsym (handle, name, &err, nullptr); if (symptr == nullptr) { - log_warn (LOG_DEFAULT, std::format ("Failed to load symbol '{}' library with handle {}. {}", name, handle, err == nullptr ? "Unknown error"sv : err)); + log_warn (LOG_DEFAULT, "Failed to load symbol '{}' library with handle {}. {}", name, handle, err == nullptr ? "Unknown error"sv : err); fnptr = nullptr; return; } diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 65cf8919eea..c01f45dabd1 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -174,12 +174,12 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] fullpath.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, std::format ("open_from_update_dir: trying to open assembly: {}", fullpath.get ())); + log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", 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) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status)); } } else { log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); @@ -191,7 +191,7 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] } if (result != nullptr && Util::should_log (LOG_ASSEMBLY)) { - log_info_nocheck (LOG_ASSEMBLY, std::format ("open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result))); + log_info_nocheck_fmt (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result)); } return result; } @@ -378,7 +378,7 @@ MonodroidRuntime::parse_gdb_options () noexcept time_t secs = time (nullptr); if (v + 10 < secs) { - log_warn (LOG_DEFAULT, std::format ("Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ())); + log_warn (LOG_DEFAULT, "Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); do_wait = false; } } @@ -449,13 +449,13 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, std::format ("Invalid SDB port value {}", sdb_port)); + log_error (LOG_DEFAULT, "Invalid SDB port value {}", sdb_port); ret = false; continue; } if (out_port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, std::format ("Invalid output port value {}", out_port)); + log_error (LOG_DEFAULT, "Invalid output port value {}", out_port); ret = false; continue; } @@ -480,7 +480,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string arg (token); - log_error (LOG_DEFAULT, std::format ("Unknown runtime argument: '{}'", arg.get ())); + log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", arg.get ()); ret = false; } } @@ -509,9 +509,9 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse cur_time = time (nullptr); if (!parse_runtime_args (runtime_args, &options)) { - log_error (LOG_DEFAULT, std::format ("Failed to parse runtime args: '{}'", runtime_args.get ())); + log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", runtime_args.get ()); } else if (options.debug && cur_time > options.timeout_time) { - log_warn (LOG_DEBUGGER, std::format ("Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time)); + log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time); } else if (options.debug && cur_time <= options.timeout_time) { EmbeddedAssemblies::set_register_debug_symbols (true); @@ -537,7 +537,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); if (options.out_port > 0) { int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -570,7 +570,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (options.server) { int accepted = monodroid_debug_accept (sock, addr); - log_warn (LOG_DEBUGGER, std::format ("Accepted stdout connection: {}", accepted)); + log_warn (LOG_DEBUGGER, "Accepted stdout connection: {}", accepted); if (accepted < 0) { Helpers::abort_application ( LOG_DEBUGGER, @@ -662,7 +662,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; - log_warn (LOG_DEBUGGER, std::format ("passing '{}' as extra arguments to the runtime.", prop_val.get ())); + log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", prop_val.get ()); char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; @@ -730,11 +730,9 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks if (user_assemblies_count == 0 && AndroidSystem::count_override_assemblies () == 0 && !is_running_on_desktop) { #if defined (DEBUG) log_fatal (LOG_DEFAULT, - std::format ( - "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", - AndroidSystem::override_dirs [0], - (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv - ) + "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", + AndroidSystem::override_dirs [0], + (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv ); #else log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"sv); @@ -859,7 +857,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec // GC threshold is 90% of the max GREF count init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); - log_info (LOG_GC, std::format ("GREF GC Threshold: {}", init.grefGcThreshold)); + log_info (LOG_GC, "GREF GC Threshold: {}", init.grefGcThreshold); init.grefClass = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); @@ -945,7 +943,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec auto initialize = reinterpret_cast (mono_method_get_unmanaged_callers_only_ftnptr (method, &error)); if (initialize == nullptr) { - log_fatal (LOG_DEFAULT, std::format ("Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error))); + log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error)); } abort_unless ( @@ -1001,7 +999,7 @@ MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstr if (createDirectory) { int rv = Util::create_directory (value.get_cstr (), mode); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, std::format ("Failed to create directory for environment variable {}. {}", name, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create directory for environment variable {}. {}", name, strerror (errno)); } setenv (name, value.get_cstr (), 1); } @@ -1011,10 +1009,10 @@ MonodroidRuntime::create_xdg_directory (jstring_wrapper& home, size_t home_len, { static_local_string dir (home_len + relative_path.length ()); Util::path_combine (dir, home.get_cstr (), home_len, relative_path.data (), relative_path.length ()); - log_debug (LOG_DEFAULT, std::format ("Creating XDG directory: {}", dir.get ())); + log_debug (LOG_DEFAULT, "Creating XDG directory: {}", dir.get ()); int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, std::format ("Failed to create XDG directory {}. {}", dir.get (), strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", dir.get (), strerror (errno)); if (!environment_variable_name.empty ()) { setenv (environment_variable_name.data (), dir.get (), 1); } @@ -1043,7 +1041,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, std::format ("Env variable '{}' set to '{}'.", name, v)); + log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", name, v); }; string_segment arg_token; @@ -1063,7 +1061,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept log_envvar (arg.get (), one.data ()); } else if (index == 0) { // ’=value’ - log_warn (LOG_DEFAULT, std::format ("Attempt to set environment variable without specifying name: '{}'", arg.get ())); + log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", arg.get ()); } else { // ’name=value’ arg[index] = '\0'; @@ -1143,10 +1141,10 @@ MonodroidRuntime::set_profile_options () noexcept .append (output_path.get (), output_path.length ()); } if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno)); } - log_warn (LOG_DEFAULT, std::format ("Initializing profiler with options: {}", value.get ())); + log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", value.get ()); debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } @@ -1471,7 +1469,7 @@ 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, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); + log_debug (LOG_DEFAULT, "Using runtime path: {}", AndroidSystem::get_runtime_libdir ()); } AndroidSystem::setup_process_args (runtimeApks); @@ -1536,15 +1534,14 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (Util::should_log (LOG_DEFAULT)) [[unlikely]] { log_info_nocheck_fmt ( LOG_DEFAULT, - std::format (".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", - BuildInfo::xa_version.data (), - BuildInfo::architecture.data (), - BuildInfo::kind.data (), - BuildInfo::date.data (), - BuildInfo::ndk_version.data (), - BuildInfo::ndk_api_level.data (), - mono_get_runtime_build_info () - ) + ".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", + BuildInfo::xa_version.data (), + BuildInfo::architecture.data (), + BuildInfo::kind.data (), + BuildInfo::date.data (), + BuildInfo::ndk_version.data (), + BuildInfo::ndk_api_level.data (), + mono_get_runtime_build_info () ); } @@ -1667,7 +1664,7 @@ MonodroidRuntime::get_java_class_name_for_TypeManager (jclass klass) noexcept JNIEnv *env = osBridge.ensure_jnienv (); jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); if (name == nullptr) { - log_error (LOG_DEFAULT, std::format ("Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass))); + log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); return nullptr; } diff --git a/src/native/mono/monodroid/monodroid-networkinfo.cc b/src/native/mono/monodroid/monodroid-networkinfo.cc index f9dcba4c181..4e87c0079d3 100644 --- a/src/native/mono/monodroid/monodroid-networkinfo.cc +++ b/src/native/mono/monodroid/monodroid-networkinfo.cc @@ -88,14 +88,14 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo networkInterface = env->CallStaticObjectMethod (NetworkInterface_class, NetworkInterface_getByName, NetworkInterface_nameArg); env->DeleteLocalRef (NetworkInterface_nameArg); if (env->ExceptionOccurred ()) { - log_warn (LOG_NET, std::format ("Java exception occurred while looking up the interface '{}'", ifname)); + log_warn (LOG_NET, "Java exception occurred while looking up the interface '{}'", ifname); env->ExceptionDescribe (); env->ExceptionClear (); goto leave; } if (!networkInterface) { - log_warn (LOG_NET, std::format ("Failed to look up interface '{}' using Java API", ifname)); + log_warn (LOG_NET, "Failed to look up interface '{}' using Java API", ifname); ret = FALSE; goto leave; } @@ -118,7 +118,7 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo leave: if (!ret) - log_warn (LOG_NET, std::format ("Unable to determine interface '{}' state using Java API", ifname)); + log_warn (LOG_NET, "Unable to determine interface '{}' state using Java API", ifname); if (networkInterface != nullptr && env != nullptr) { env->DeleteLocalRef (networkInterface); diff --git a/src/native/mono/monodroid/monodroid-tracing.cc b/src/native/mono/monodroid/monodroid-tracing.cc index 892a5938393..adb9f0db1d6 100644 --- a/src/native/mono/monodroid/monodroid-tracing.cc +++ b/src/native/mono/monodroid/monodroid-tracing.cc @@ -27,7 +27,7 @@ MonodroidRuntime::log_traces (JNIEnv *env, TraceKind kind, const char *first_lin char *err = nullptr; void *handle = MonodroidDl::monodroid_dlopen (SharedConstants::xamarin_native_tracing_name.data (), MONO_DL_EAGER, &err, nullptr); if (handle == nullptr) { - log_warn (LOG_DEFAULT, std::format ("Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err)); + log_warn (LOG_DEFAULT, "Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err); } else { load_symbol (handle, "xa_get_native_backtrace", _xa_get_native_backtrace); load_symbol (handle, "xa_get_managed_backtrace", _xa_get_managed_backtrace); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 612e6c44c5e..727e277d501 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -186,7 +186,7 @@ OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) *end = '\0'; if ((category == LOG_GREF && gref_to_logcat) || (category == LOG_LREF && lref_to_logcat)) { - log_debug (category, std::format ("{}", m)); + log_debug (category, "{}", m); } if (to != nullptr) { fprintf (to, "%s\n", optional_string (m)); @@ -200,7 +200,7 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, std::format ("{}", message)); + log_debug (LOG_GREF, "{}", message); } if (!gref_log) return; @@ -215,22 +215,21 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH if ((log_categories & LOG_GREF) == 0) return c; log_info (LOG_GREF, - std::format ("+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - threadName, - threadId - ) + "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -261,20 +260,19 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - std::format ("-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -301,22 +299,21 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - std::format ("+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - threadName, - threadId - ) + "+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -345,20 +342,19 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - std::format ("-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -384,19 +380,18 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - std::format ("+l+ lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "+l+ lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!lref_log) @@ -421,19 +416,18 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - std::format ("-l- lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "-l- lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!lref_log) @@ -546,11 +540,9 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) i = get_gc_bridge_index (klass); if (i == static_cast (-NUM_GC_BRIDGE_TYPES)) { log_info (LOG_GC, - std::format ( - "asked if a class {}.{} is a bridge before we inited java.lang.Object", - mono_class_get_namespace (klass), - mono_class_get_name (klass) - ) + "asked if a class {}.{} is a bridge before we inited java.lang.Object", + mono_class_get_namespace (klass), + mono_class_get_name (klass) ); return MonoGCBridgeObjectKind::GC_BRIDGE_TRANSPARENT_CLASS; } @@ -576,11 +568,9 @@ OSBridge::gc_is_bridge_object (MonoObject *object) #if DEBUG MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, - std::format ( - "object of class {}.{} with null handle", - mono_class_get_namespace (mclass), - mono_class_get_name (mclass) - ) + "object of class {}.{} with null handle", + mono_class_get_namespace (mclass), + mono_class_get_name (mclass) ); #endif return 0; @@ -667,9 +657,9 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri *reffed_description = describe_target (reffed_target); if (success) - log_warn (LOG_GC, std::format ("Added reference for {} to {}", description, reffed_description)); + log_warn (LOG_GC, "Added reference for {} to {}", description, reffed_description); else - log_error (LOG_GC, std::format ("Missing monodroidAddReference method for {}", description)); + log_error (LOG_GC, "Missing monodroidAddReference method for {}", description); free (description); free (reffed_description); @@ -906,11 +896,9 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (Logger::gc_spew_enabled ()) { klass = mono_object_get_class (obj); log_error (LOG_GC, - std::format ( - "Missing monodroidClearReferences method for object of class {}.{}", - mono_class_get_namespace (klass), - mono_class_get_name (klass) - ) + "Missing monodroidClearReferences method for object of class {}.{}", + mono_class_get_namespace (klass), + mono_class_get_name (klass) ); } #endif @@ -925,7 +913,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } } #if DEBUG - log_info (LOG_GC, std::format ("GC cleanup summary: {} objects tested - resurrecting {}.", total, alive)); + log_info (LOG_GC, "GC cleanup summary: {} objects tested - resurrecting {}.", total, alive); #endif } @@ -955,10 +943,10 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre if (Logger::gc_spew_enabled ()) { int i, j; - log_info (LOG_GC, std::format ("cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs)); + log_info (LOG_GC, "cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs); for (i = 0; i < num_sccs; ++i) { - log_info (LOG_GC, std::format ("group {} with {} objects", i, sccs [i]->num_objs)); + log_info (LOG_GC, "group {} with {} objects", i, sccs [i]->num_objs); for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; @@ -973,21 +961,19 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre } MonoClass *klass = mono_object_get_class (obj); log_info (LOG_GC, - std::format ( - "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", - reinterpret_cast(obj), - mono_class_get_namespace (klass), - mono_class_get_name (klass), - reinterpret_cast(handle), - key_handle - ) + "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", + reinterpret_cast(obj), + mono_class_get_namespace (klass), + mono_class_get_name (klass), + reinterpret_cast(handle), + key_handle ); } } if (Util::should_log (LOG_GC)) { for (i = 0; i < num_xrefs; ++i) - log_info_nocheck (LOG_GC, std::format ("xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index)); + log_info_nocheck_fmt (LOG_GC, "xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); } } diff --git a/src/native/mono/monodroid/xamarin-android-app-context.cc b/src/native/mono/monodroid/xamarin-android-app-context.cc index e55635f2443..75973eb020e 100644 --- a/src/native/mono/monodroid/xamarin-android-app-context.cc +++ b/src/native/mono/monodroid/xamarin-android-app-context.cc @@ -15,7 +15,7 @@ MonodroidRuntime::get_method_name (uint32_t mono_image_index, uint32_t method_to { uint64_t id = (static_cast(mono_image_index) << 32) | method_token; - log_debug (LOG_ASSEMBLY, std::format ("MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index)); + log_debug (LOG_ASSEMBLY, "MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index); size_t i = 0uz; while (mm_method_names[i].id != 0) { if (mm_method_names[i].id == id) { @@ -43,10 +43,9 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas { log_debug ( LOG_ASSEMBLY, - std::format ("MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", - get_method_name (mono_image_index, method_token), method_token, - get_class_name (class_index), class_index - ) + "MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", + get_method_name (mono_image_index, method_token), method_token, + get_class_name (class_index), class_index ); if (class_index >= marshal_methods_number_of_classes) [[unlikely]] { @@ -81,32 +80,29 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, - std::format ("Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", - mono_method_full_name (method, true), - ret, - mono_image_index, - class_index, - method_token - ) + "Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", + mono_method_full_name (method, true), + ret, + mono_image_index, + class_index, + method_token ); return; } log_fatal ( LOG_DEFAULT, - std::format ("Failed to obtain function pointer to method '{}' in class '{}'", - get_method_name (mono_image_index, method_token), - get_class_name (class_index) - ) + "Failed to obtain function pointer to method '{}' in class '{}'", + get_method_name (mono_image_index, method_token), + get_class_name (class_index) ); log_fatal ( LOG_DEFAULT, - std::format ("Looked for image index {}, class index {}, method token {:x}", - mono_image_index, - class_index, - method_token - ) + "Looked for image index {}, class index {}, method token {:x}", + mono_image_index, + class_index, + method_token ); if (image == nullptr) { diff --git a/src/native/mono/monodroid/xamarin_getifaddrs.cc b/src/native/mono/monodroid/xamarin_getifaddrs.cc index 99ba01039e6..57c4935a7bf 100644 --- a/src/native/mono/monodroid/xamarin_getifaddrs.cc +++ b/src/native/mono/monodroid/xamarin_getifaddrs.cc @@ -421,7 +421,7 @@ open_netlink_session (netlink_session *session) memset (session, 0, sizeof (*session)); session->sock_fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (session->sock_fd == -1) { - log_warn (LOG_NETLINK, std::format ("Failed to create a netlink socket. {}", strerror (errno))); + log_warn (LOG_NETLINK, "Failed to create a netlink socket. {}", strerror (errno)); return -1; } @@ -440,7 +440,7 @@ open_netlink_session (netlink_session *session) session->them.nl_family = AF_NETLINK; if (bind (session->sock_fd, (struct sockaddr *)&session->us, sizeof (session->us)) < 0) { - log_warn (LOG_NETLINK, std::format ("Failed to bind to the netlink socket. {}", strerror (errno))); + log_warn (LOG_NETLINK, "Failed to bind to the netlink socket. {}", strerror (errno)); return -1; } @@ -478,7 +478,7 @@ send_netlink_dump_request (netlink_session *session, int type) session->message_header.msg_iov = &session->payload_vector; if (sendmsg (session->sock_fd, (const struct msghdr*)&session->message_header, 0) < 0) { - log_warn (LOG_NETLINK, std::format ("Failed to send netlink message. {}", strerror (errno))); + log_warn (LOG_NETLINK, "Failed to send netlink message. {}", strerror (errno)); return -1; } @@ -529,7 +529,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd abort_if_invalid_pointer_argument (last_ifaddr, "last_ifaddr"); size_t buf_size = static_cast(getpagesize ()); - log_debug (LOG_NETLINK, std::format ("receive buffer size == {}", buf_size)); + log_debug (LOG_NETLINK, "receive buffer size == {}", buf_size); size_t alloc_size = Helpers::multiply_with_overflow_check (sizeof(*response), buf_size); response = (unsigned char*)malloc (alloc_size); @@ -551,10 +551,10 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd netlink_reply.msg_iov = &reply_vector; length = recvmsg (session->sock_fd, &netlink_reply, 0); - log_debug (LOG_NETLINK, std::format (" length == {}", (int)length)); + log_debug (LOG_NETLINK, " length == {}", (int)length); if (length < 0) { - log_debug (LOG_NETLINK, std::format ("Failed to receive reply from netlink. {}", strerror (errno))); + log_debug (LOG_NETLINK, "Failed to receive reply from netlink. {}", strerror (errno)); goto cleanup; } @@ -582,7 +582,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; for (current_message = (struct nlmsghdr*)response; current_message && NLMSG_OK (current_message, static_cast(length)); current_message = NLMSG_NEXT (current_message, length)) { - log_debug (LOG_NETLINK, std::format ("next message... (type: {})", current_message->nlmsg_type)); + log_debug (LOG_NETLINK, "next message... (type: {})", current_message->nlmsg_type); switch (current_message->nlmsg_type) { /* See rtnetlink.h */ case RTM_NEWLINK: @@ -611,7 +611,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; default: - log_debug (LOG_NETLINK, std::format (" message type: {}", current_message->nlmsg_type)); + log_debug (LOG_NETLINK, " message type: {}", current_message->nlmsg_type); break; } } @@ -634,7 +634,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET: { struct sockaddr_in *sa4; if (rta_payload_length != 4) /* IPv4 address length */ { - log_warn (LOG_NETLINK, std::format ("Unexpected IPv4 address payload length {}", rta_payload_length)); + log_warn (LOG_NETLINK, "Unexpected IPv4 address payload length {}", rta_payload_length); return -1; } sa4 = (struct sockaddr_in*)calloc (1, sizeof (*sa4)); @@ -650,7 +650,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET6: { struct sockaddr_in6 *sa6; if (rta_payload_length != 16) /* IPv6 address length */ { - log_warn (LOG_NETLINK, std::format ("Unexpected IPv6 address payload length {}", rta_payload_length)); + log_warn (LOG_NETLINK, "Unexpected IPv6 address payload length {}", rta_payload_length); return -1; } sa6 = (struct sockaddr_in6*)calloc (1, sizeof (*sa6)); @@ -668,7 +668,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ default: { struct sockaddr *sagen; if (rta_payload_length > sizeof (sagen->sa_data)) { - log_warn (LOG_NETLINK, std::format ("Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data))); + log_warn (LOG_NETLINK, "Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data)); return -1; } @@ -701,9 +701,9 @@ fill_ll_address (struct sockaddr_ll_extended **sa, struct ifinfomsg *net_interfa /* The assert can only fail for Iniband links, which are quite unlikely to be found * in any mobile devices */ - log_debug (LOG_NETLINK, std::format ("rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type)); + log_debug (LOG_NETLINK, "rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type); if (static_cast(rta_payload_length) > sizeof ((*sa)->sll_addr)) { - log_info (LOG_NETLINK, std::format ("Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr))); + log_info (LOG_NETLINK, "Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr)); free (*sa); *sa = NULL; return -1; @@ -817,14 +817,14 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net memset (netmask_data, 0xFF, prefix_bytes); if (postfix_bytes > 0) memset (netmask_data + prefix_bytes + 1, 0x00, postfix_bytes); - log_debug (LOG_NETLINK, std::format (" calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length)); + log_debug (LOG_NETLINK, " calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length); 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 (Util::should_log (LOG_NETLINK)) { log_debug_nocheck (LOG_NETLINK, " netmask is: "sv); for (uint32_t i = 0; i < data_length; i++) { - log_debug_nocheck (LOG_NETLINK, std::format ("{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i])); + log_debug_nocheck_fmt (LOG_NETLINK, "{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i]); } } } @@ -847,7 +847,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if abort_if_invalid_pointer_argument (message, "message"); net_address = reinterpret_cast (NLMSG_DATA (message)); length = static_cast(IFA_PAYLOAD (message)); - log_debug (LOG_NETLINK, std::format (" address data length: {}", length)); + log_debug (LOG_NETLINK, " address data length: {}", length); if (length <= 0) { goto error; } @@ -864,7 +864,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " reading attributes"sv); while (RTA_OK (attribute, length)) { payload_size = RTA_PAYLOAD (attribute); - log_debug (LOG_NETLINK, std::format (" attribute payload_size == {}", payload_size)); + log_debug (LOG_NETLINK, " attribute payload_size == {}", payload_size); sa = NULL; switch (attribute->rta_type) { @@ -943,7 +943,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; default: - log_debug (LOG_NETLINK, std::format (" attribute type: {}", attribute->rta_type)); + log_debug (LOG_NETLINK, " attribute type: {}", attribute->rta_type); break; } @@ -962,7 +962,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " address has no name/label, getting one from interface"sv); ifa->ifa_name = name ? strdup (name) : NULL; } - log_debug (LOG_NETLINK, std::format (" address label: {}", ifa->ifa_name)); + log_debug (LOG_NETLINK, " address label: {}", ifa->ifa_name); if (calculate_address_netmask (ifa, net_address) < 0) { goto error; @@ -1016,13 +1016,13 @@ get_link_info (const struct nlmsghdr *message) goto error; } if (Util::should_log (LOG_NETLINK)) { - log_debug_nocheck (LOG_NETLINK, std::format (" interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name))); - log_debug_nocheck (LOG_NETLINK, std::format (" {}", ifa->ifa_name)); + log_debug_nocheck_fmt (LOG_NETLINK, " interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); + log_debug_nocheck_fmt (LOG_NETLINK, " {}", ifa->ifa_name); } break; case IFLA_BROADCAST: - log_debug (LOG_NETLINK, std::format (" interface broadcast ({} bytes)", RTA_PAYLOAD (attribute))); + log_debug (LOG_NETLINK, " interface broadcast ({} bytes)", RTA_PAYLOAD (attribute)); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1030,7 +1030,7 @@ get_link_info (const struct nlmsghdr *message) break; case IFLA_ADDRESS: - log_debug (LOG_NETLINK, std::format (" interface address ({} bytes)", RTA_PAYLOAD (attribute))); + log_debug (LOG_NETLINK, " interface address ({} bytes)", RTA_PAYLOAD (attribute)); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1047,7 +1047,7 @@ get_link_info (const struct nlmsghdr *message) attribute = RTA_NEXT (attribute, length); } - log_debug (LOG_NETLINK, std::format ("link flags: {:X}", ifa->ifa_flags)); + log_debug (LOG_NETLINK, "link flags: {:X}", ifa->ifa_flags); return ifa; error: @@ -1142,7 +1142,7 @@ print_ifla_name (int id) int i = 0; while (1) { if (iflas [i].value == -1 && iflas [i].name == 0) { - log_info_nocheck (LOG_NETLINK, std::format ("Unknown ifla->name: unknown id {}", id)); + log_info_nocheck_fmt (LOG_NETLINK, "Unknown ifla->name: unknown id {}", id); break; } @@ -1150,7 +1150,7 @@ print_ifla_name (int id) i++; continue; } - log_info_nocheck (LOG_NETLINK, std::format ("ifla->name: {} ({})", iflas [i].name, iflas [i].value)); + log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", iflas [i].name, iflas [i].value); break; } } @@ -1165,7 +1165,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) char *msg, *tmp; if (!list) { - log_info_nocheck (LOG_NETLINK, std::format ("No list to print in {}", __FUNCTION__)); + log_info_nocheck_fmt (LOG_NETLINK, "No list to print in {}", __FUNCTION__); return; } @@ -1180,7 +1180,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) cur = cur->ifa_next; } - log_info_nocheck (LOG_NETLINK, std::format ("{}: {}", title, msg ? msg : "[no addresses]"sv)); + log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, msg ? msg : "[no addresses]"sv); free (msg); } #endif diff --git a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh index 240223b396c..f6c402c46e7 100644 --- a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh @@ -23,21 +23,21 @@ namespace xamarin::android { constexpr bool PREFER_AOT_CACHE = false; lib_handle = internal::MonodroidDl::monodroid_dlopen (library_name, MONO_DL_LOCAL, nullptr, PREFER_AOT_CACHE); if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name)); + log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name); return nullptr; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, std::format ("Library '{}' handle already cached by another thread", library_name)); + log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", library_name); } } } void *entry_handle = internal::MonodroidDl::monodroid_dlsym (lib_handle, symbol_name, nullptr, nullptr); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name)); + log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name); return nullptr; } @@ -60,7 +60,7 @@ namespace xamarin::android { return nullptr; } - log_debug (LOG_ASSEMBLY, std::format ("Caching p/invoke entry {} @ {}", library_name, entrypoint_name)); + log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); (*api_map)[entrypoint_name] = entry_handle; return entry_handle; } @@ -81,7 +81,7 @@ namespace xamarin::android { ); if (already_loaded) { - log_debug (LOG_ASSEMBLY, std::format ("Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name)); + log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); } } @@ -147,7 +147,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("Internal error: null entry in p/invoke map for key '{}'", library_name)); + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", library_name); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index 1ef4bbfaba0..e5c54608ff3 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -22,11 +22,11 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, std::format ("Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash)); + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, std::format ("\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash)); + log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash); } Helpers::abort_application ( LOG_ASSEMBLY, @@ -67,7 +67,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, std::format ("Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name)); + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name); return nullptr; // let Mono deal with the fallout } @@ -75,7 +75,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha } // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below - log_debug (LOG_ASSEMBLY, std::format ("Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name)); + log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name); } return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index d092be238cc..78d59b70bfa 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -65,7 +65,7 @@ AndroidSystem::lookup_system_property (const char *name, size_t &value_len) noex return nullptr; if (application_config.system_property_count % 2 != 0) { - log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count)); + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count); return nullptr; } @@ -138,7 +138,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 = Helpers::add_with_overflow_check (PROPERTY_VALUE_BUFFER_LEN, 1uz); - log_warn (LOG_DEFAULT, std::format ("Buffer to store system property may be too small, will copy only {} bytes", sp_value_len)); + log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); buf = new char [alloc_size]; } @@ -250,12 +250,12 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co } std::unique_ptr override_file {Util::path_combine (od, name)}; - log_info (LOG_DEFAULT, std::format ("Trying to get property from {}", override_file.get ())); + log_info (LOG_DEFAULT, "Trying to get property from {}", 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') { continue; } - log_info (LOG_DEFAULT, std::format ("Property '{}' from {} has value '{}'.", name, od, *value)); + log_info (LOG_DEFAULT, "Property '{}' from {} has value '{}'.", name, od, *value); return result; } #endif // def DEBUG @@ -281,7 +281,7 @@ AndroidSystem::create_update_dir (char *override_dir) noexcept override_dirs [0] = override_dir; Util::create_public_directory (override_dir); - log_warn (LOG_DEFAULT, std::format ("Creating public update directory: `{}`", override_dir)); + log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); } bool @@ -306,16 +306,16 @@ AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exis if (path == nullptr || *path == '\0') return nullptr; - log_info (LOG_ASSEMBLY, std::format ("Trying to load shared library '{}'", path)); + log_info (LOG_ASSEMBLY, "Trying to load shared library '{}'", path); if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { - log_info (LOG_ASSEMBLY, std::format ("Shared library '{}' not found", path)); + log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); return nullptr; } char *error = nullptr; void *handle = java_interop_lib_load (path, dl_flags, &error); if (handle == nullptr && Util::should_log (LOG_ASSEMBLY)) - log_info_nocheck (LOG_ASSEMBLY, std::format ("Failed to load shared library '{}'. {}", path, error)); + log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '{}'. {}", path, error); java_interop_free (error); return handle; } @@ -450,9 +450,9 @@ AndroidSystem::get_max_gref_count_from_system (void) noexcept if (max < 0) max = std::numeric_limits::max (); if (*e) { - log_warn (LOG_GC, std::format ("Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ())); + log_warn (LOG_GC, "Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); } - log_warn (LOG_GC, std::format ("Overriding max JNI Global Reference count to {}", max)); + log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); } return max; } @@ -478,7 +478,7 @@ AndroidSystem::setup_environment (const char *name, const char *value) noexcept if (isupper (name [0]) || name [0] == '_') { if (setenv (name, v, 1) < 0) - log_warn (LOG_DEFAULT, std::format ("(Debug) Failed to set environment variable: {}", strerror (errno))); + log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); return; } @@ -492,13 +492,13 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept struct stat sbuf; if (::stat (path, &sbuf) < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to stat the environment override file {}: {}", path, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to stat the environment override file {}: {}", path, strerror (errno)); return; } int fd = open (path, O_RDONLY); if (fd < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to open the environment override file {}: {}", path, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to open the environment override file {}: {}", path, strerror (errno)); return; } @@ -515,7 +515,7 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept } while (r < 0 && errno == EINTR); if (nread == 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to read the environment override file {}: {}", path, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to read the environment override file {}: {}", path, strerror (errno)); return; } @@ -536,26 +536,26 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept // # Variable value, terminated with NUL and padded to [value width] with NUL characters // value\0 if (nread < OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) { - log_warn (LOG_DEFAULT, std::format ("Invalid format of the environment override file {}: malformatted header", path)); + log_warn (LOG_DEFAULT, "Invalid format of the environment override file {}: malformatted header", path); return; } char *endptr; unsigned long name_width = strtoul (buf.get (), &endptr, 16); if ((name_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: name width has invalid format", path)); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path); return; } unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: value width has invalid format", path)); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path); return; } uint64_t data_width = name_width + value_width; if (data_width > file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: invalid data size", path)); + log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path); return; } @@ -563,11 +563,11 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept char *name = buf.get () + OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE; while (data_size > 0 && data_size >= data_width) { if (*name == '\0') { - log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ())); + log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ()); return; } - log_debug (LOG_DEFAULT, std::format ("Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width)); + log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width); setup_environment (name, name + name_width); name += data_width; data_size -= data_width; @@ -602,10 +602,10 @@ AndroidSystem::setup_environment () noexcept } if (aotMode != MonoAotMode::MONO_AOT_MODE_LAST) { - log_debug (LOG_DEFAULT, std::format ("Mono AOT mode: {}", mono_aot_mode_name)); + log_debug (LOG_DEFAULT, "Mono AOT mode: {}", mono_aot_mode_name); } else { if (!is_interpreter_enabled ()) { - log_warn (LOG_DEFAULT, std::format ("Unknown Mono AOT mode: {}", mono_aot_mode_name)); + log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: {}", mono_aot_mode_name); } else { log_warn (LOG_DEFAULT, "Mono AOT mode: interpreter"sv); } @@ -613,7 +613,7 @@ AndroidSystem::setup_environment () noexcept } if (application_config.environment_variable_count % 2 != 0) { - log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count)); + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count); return; } @@ -629,10 +629,10 @@ AndroidSystem::setup_environment () noexcept var_value = ""; #if defined (DEBUG) - log_info (LOG_DEFAULT, std::format ("Setting environment variable '{}' to '{}'", var_name, var_value)); + log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); #endif // def DEBUG if (setenv (var_name, var_value, 1) < 0) - log_warn (LOG_DEFAULT, std::format ("Failed to set environment variable: {}", strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); } #if defined (DEBUG) log_debug (LOG_DEFAULT, "Loading environment from override directories."sv); @@ -641,9 +641,9 @@ AndroidSystem::setup_environment () noexcept continue; } std::unique_ptr env_override_file {Util::path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; - log_debug (LOG_DEFAULT, std::format ("{}", env_override_file.get ())); + log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); if (Util::file_exists (env_override_file.get ())) { - log_debug (LOG_DEFAULT, std::format ("Loading {}", env_override_file.get ())); + log_debug (LOG_DEFAULT, "Loading {}", env_override_file.get ()); setup_environment_from_override_file (env_override_file.get ()); } } @@ -671,12 +671,12 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep { // 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, std::format ("Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ())); + log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); if (!Util::file_exists (libmonodroid_path.get ())) { - log_debug (LOG_ASSEMBLY, std::format ("{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ())); + log_debug (LOG_ASSEMBLY, "{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); set_embedded_dso_mode_enabled (true); } else { - log_debug (LOG_ASSEMBLY, std::format ("Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); + log_debug (LOG_ASSEMBLY, "Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); set_embedded_dso_mode_enabled (false); } } @@ -689,7 +689,7 @@ AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks 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, std::format ("Added filesystem DSO lookup location: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); + log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); } else { log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); @@ -725,7 +725,7 @@ AndroidSystem::add_apk_libdir (const char *apk, size_t &index, const char *abi) { 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, std::format ("Added APK DSO lookup location: {}", app_lib_directories[index])); + log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: {}", app_lib_directories[index]); index++; } diff --git a/src/native/mono/runtime-base/logger.cc b/src/native/mono/runtime-base/logger.cc index f11c9aa52ad..de5f6dee5cf 100644 --- a/src/native/mono/runtime-base/logger.cc +++ b/src/native/mono/runtime-base/logger.cc @@ -11,8 +11,8 @@ #include #include "android-system.hh" -#include -#include +#include "cpp-util.hh" +#include "log_level.hh" #include "logger.hh" #include "shared-constants.hh" #include "util.hh" diff --git a/src/native/mono/runtime-base/monodroid-dl.hh b/src/native/mono/runtime-base/monodroid-dl.hh index 621d0744fe7..93cb8b70b48 100644 --- a/src/native/mono/runtime-base/monodroid-dl.hh +++ b/src/native/mono/runtime-base/monodroid-dl.hh @@ -48,11 +48,11 @@ namespace xamarin::android::internal size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in AOT cache", hash)); + log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in DSO cache", hash)); + log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } @@ -102,7 +102,7 @@ namespace xamarin::android::internal if (MonodroidState::is_startup_in_progress ()) { auto ignore_component = [&](const char *label, MonoComponent component) -> bool { if ((application_config.mono_components_mask & component) != component) { - log_info (LOG_ASSEMBLY, std::format ("Mono '{}' component requested but not packaged, ignoring", label)); + log_info (LOG_ASSEMBLY, "Mono '{}' component requested but not packaged, ignoring", label); return true; } @@ -150,7 +150,7 @@ namespace xamarin::android::internal } hash_t name_hash = xxhash::hash (name, strlen (name)); - log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash)); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash); DSOCacheEntry *dso = nullptr; if (prefer_aot_cache) { @@ -167,7 +167,7 @@ namespace xamarin::android::internal dso = find_only_dso_cache_entry (name_hash); } - log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name)); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name); if (dso == nullptr) { // DSO not known at build time, try to load it @@ -177,7 +177,7 @@ namespace xamarin::android::internal } if (dso->ignore) { - log_info (LOG_ASSEMBLY, std::format ("Request to load '{}' ignored, it is known not to exist", dso->name)); + log_info (LOG_ASSEMBLY, "Request to load '{}' ignored, it is known not to exist", dso->name); return nullptr; } diff --git a/src/native/mono/runtime-base/timing-internal.cc b/src/native/mono/runtime-base/timing-internal.cc index 7b23705d880..6efcfdae461 100644 --- a/src/native/mono/runtime-base/timing-internal.cc +++ b/src/native/mono/runtime-base/timing-internal.cc @@ -78,11 +78,11 @@ FastTiming::dump () noexcept log_write (LOG_TIMING, LogLevel::Info, "[2/4] Accumulated performance results"); ns_to_time (total_assembly_load_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, std::format (" [2/5] Assembly load: {}:{}::{}", sec, ms, ns)); + log_info_nocheck (LOG_TIMING, " [2/5] Assembly load: {}:{}::{}", sec, ms, ns); ns_to_time (total_java_to_managed_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, std::format (" [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns)); + log_info_nocheck (LOG_TIMING, " [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns); ns_to_time (total_managed_to_java_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, std::format (" [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns)); + log_info_nocheck (LOG_TIMING, " [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns); } diff --git a/src/native/mono/runtime-base/timing-internal.hh b/src/native/mono/runtime-base/timing-internal.hh index 804e2544a9d..6389e719e7e 100644 --- a/src/native/mono/runtime-base/timing-internal.hh +++ b/src/native/mono/runtime-base/timing-internal.hh @@ -144,7 +144,7 @@ namespace xamarin::android::internal // likely we'll run out of memory way, way, way before that happens size_t old_size = events.capacity (); events.reserve (old_size << 1); - log_warn (LOG_TIMING, std::format ("Reallocated timing event buffer from {} to {}", old_size, events.size ())); + log_warn (LOG_TIMING, "Reallocated timing event buffer from {} to {}", old_size, events.size ()); } } @@ -246,7 +246,7 @@ namespace xamarin::android::internal [[gnu::always_inline]] bool is_valid_event_index (size_t index, const char *method_name) noexcept { if (index >= events.capacity ()) [[unlikely]] { - log_warn (LOG_TIMING, std::format ("Invalid event index passed to method '{}'", method_name)); + log_warn (LOG_TIMING, "Invalid event index passed to method '{}'", method_name); return false; } diff --git a/src/native/mono/runtime-base/timing.hh b/src/native/mono/runtime-base/timing.hh index 31f9892e918..191ec55df2f 100644 --- a/src/native/mono/runtime-base/timing.hh +++ b/src/native/mono/runtime-base/timing.hh @@ -93,14 +93,14 @@ namespace xamarin::android { timing_diff diff (period); - log_info_nocheck (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); + log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); } static void warn (timing_period const &period, const char *message) noexcept { timing_diff diff (period); - log_warn (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); + log_warn (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); } managed_timing_sequence* get_available_sequence () noexcept diff --git a/src/native/mono/runtime-base/util.cc b/src/native/mono/runtime-base/util.cc index 388c9beb9c3..d377cc46c31 100644 --- a/src/native/mono/runtime-base/util.cc +++ b/src/native/mono/runtime-base/util.cc @@ -150,7 +150,7 @@ Util::create_public_directory (const char *dir) mode_t m = umask (0); int ret = mkdir (dir, 0777); if (ret < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", dir, std::strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); } umask (m); } @@ -198,7 +198,7 @@ Util::set_world_accessable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, std::format ("chmod(\"{}\", 0664) failed: {}", path, strerror (errno))); + log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); } } @@ -211,7 +211,7 @@ Util::set_user_executable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, std::format ("chmod(\"{}\") failed: {}", path, strerror (errno))); + log_error (LOG_DEFAULT, "chmod(\"{}\") failed: {}", path, strerror (errno)); } } @@ -298,7 +298,7 @@ Util::monodroid_fopen (const char *filename, const char *mode) */ ret = fopen (filename, mode); if (ret == nullptr) { - log_error (LOG_DEFAULT, std::format ("fopen failed for file {}: {}", filename, strerror (errno))); + log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); return nullptr; } diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 2c553ff63a6..3dbdeae10bc 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -80,7 +80,7 @@ namespace xamarin::android { struct stat sbuf; if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to stat file '{}': {}", file_name, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Failed to stat file '{}': {}", file_name, std::strerror (errno)); return std::nullopt; } @@ -91,7 +91,7 @@ namespace xamarin::android { int fd = openat (dirfd, file_name, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, std::format ("Failed to open file '{}' for reading: {}", file_name, std::strerror (errno))); + log_error (LOG_ASSEMBLY, "Failed to open file '{}' for reading: {}", file_name, std::strerror (errno)); return std::nullopt; } diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index 1c0e5cfd30e..f2f03b9d5b6 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -86,7 +86,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l // 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, std::format ("loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ())); + log_info_nocheck (LOG_DEFAULT, "loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); } namespace xamarin::android diff --git a/src/native/mono/shared/helpers.cc b/src/native/mono/shared/helpers.cc index 645f30e0d84..9638b16ebd5 100644 --- a/src/native/mono/shared/helpers.cc +++ b/src/native/mono/shared/helpers.cc @@ -11,7 +11,7 @@ using namespace xamarin::android; Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept { // Log it, but also... - log_fatal (category, std::string_view { message }); + log_fatal (category, "{}", message); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -35,12 +35,11 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - std::format ("Abort at {}:{}:{} ('%s')", - file_name, - sloc.line (), - sloc.column (), - sloc.function_name () - ) + "Abort at {}:{}:{} ('%s')", + file_name, + sloc.line (), + sloc.column (), + sloc.function_name () ); } std::abort (); diff --git a/src/native/mono/shared/log_functions.cc b/src/native/mono/shared/log_functions.cc index e82f2bd5856..c6d61f54d0d 100644 --- a/src/native/mono/shared/log_functions.cc +++ b/src/native/mono/shared/log_functions.cc @@ -3,8 +3,8 @@ #include -//#include "java-interop-logger.h" -#include "log_types.hh" +#include "java-interop-logger.h" +#include "log_level.hh" // Must match the same ordering as LogCategories static constexpr std::array log_names = { diff --git a/src/native/mono/shared/log_level.hh b/src/native/mono/shared/log_level.hh new file mode 100644 index 00000000000..fc7a7566910 --- /dev/null +++ b/src/native/mono/shared/log_level.hh @@ -0,0 +1,26 @@ +#pragma once + +#include + +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 + }; +} diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index 711317c7a08..1d3dc1ce812 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -48,7 +48,7 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); + log_warn (LOG_DEFAULT, "Using runtime path: {}", AndroidSystem::get_runtime_libdir ()); } const char *monosgen_path = get_libmonosgen_path (); @@ -74,10 +74,8 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) break; log_warn (LOG_DEFAULT, - std::format ( - "Copying file `{}` from external location `{}` to internal location `{}`", - file, from_dir, to_dir - ) + "Copying file `{}` from external location `{}` to internal location `{}`", + file, from_dir, to_dir ); to_file = Util::path_combine (to_dir, file); @@ -86,12 +84,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) int r = unlink (to_file); if (r < 0 && errno != ENOENT) { - log_warn (LOG_DEFAULT, std::format ("Unable to delete file `{}`: {}", to_file, strerror (errno))); + log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", to_file, strerror (errno)); break; } if (!Util::file_copy (to_file, from_file)) { - log_warn (LOG_DEFAULT, std::format ("Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno))); + log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno)); break; } @@ -110,22 +108,22 @@ copy_native_libraries_to_internal_location () dirent *e; char *dir_path = Util::path_combine (od, "lib"); - log_warn (LOG_DEFAULT, std::format ("checking directory: `{}`", dir_path)); + log_warn (LOG_DEFAULT, "checking directory: `{}`", dir_path); if (dir_path == nullptr || !Util::directory_exists (dir_path)) { - log_warn (LOG_DEFAULT, std::format ("directory does not exist: `{}`", dir_path)); + log_warn (LOG_DEFAULT, "directory does not exist: `{}`", dir_path); delete[] dir_path; continue; } if ((dir = ::opendir (dir_path)) == nullptr) { - log_warn (LOG_DEFAULT, std::format ("could not open directory: `{}`", dir_path)); + log_warn (LOG_DEFAULT, "could not open directory: `{}`", dir_path); delete[] dir_path; continue; } while ((e = readdir (dir)) != nullptr) { - log_warn (LOG_DEFAULT, std::format ("checking file: `{}`", e->d_name)); + log_warn (LOG_DEFAULT, "checking file: `{}`", 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); } @@ -142,9 +140,9 @@ runtime_exists (const char *dir, char*& libmonoso) return false; libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); - log_warn (LOG_DEFAULT, std::format ("Checking whether Mono runtime exists at: {}", libmonoso)); + log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", libmonoso); if (Util::file_exists (libmonoso)) { - log_info (LOG_DEFAULT, std::format ("Mono runtime found at: {}", libmonoso)); + log_info (LOG_DEFAULT, "Mono runtime found at: {}", libmonoso); return true; } delete[] libmonoso; @@ -196,25 +194,25 @@ get_libmonosgen_path () if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { - log_warn (LOG_DEFAULT, std::format ("symlink exists, recreating: {} -> {}", link, libmonoso)); + log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", link, libmonoso); unlink (link); result = symlink (libmonoso, link); } if (result != 0) - log_warn (LOG_DEFAULT, std::format ("symlink failed with errno={} {}", errno, strerror (errno))); + log_warn (LOG_DEFAULT, "symlink failed with errno={} {}", errno, strerror (errno)); } delete[] libmonoso; libmonoso = link; } - log_warn (LOG_DEFAULT, std::format ("Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv)); + log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv); if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; if (runtime_exists (AndroidSystem::SYSTEM_LIB_PATH.data (), libmonoso)) return libmonoso; - log_fatal (LOG_DEFAULT, std::format ("Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO)); + log_fatal (LOG_DEFAULT, "Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO); for (const char *od : AndroidSystem::override_dirs) { if (od == nullptr) From 3b538c367a210099a7768e8c15c41e4b96d8ffd3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 29 Nov 2024 09:54:16 +0100 Subject: [PATCH 019/143] Cleanup --- src/native/common/include/shared/helpers.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/native/common/include/shared/helpers.hh b/src/native/common/include/shared/helpers.hh index 22e29b40f25..587c48a7f76 100644 --- a/src/native/common/include/shared/helpers.hh +++ b/src/native/common/include/shared/helpers.hh @@ -6,6 +6,7 @@ #include #include +#include "platform-compat.hh" using namespace std::string_view_literals; From e6d322409f79dbfe0ba2653b3f838ed434989c6e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 29 Nov 2024 10:01:06 +0100 Subject: [PATCH 020/143] Cleanup --- src/native/mono/runtime-base/internal-pinvokes.hh | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/mono/runtime-base/internal-pinvokes.hh b/src/native/mono/runtime-base/internal-pinvokes.hh index 1fbfc4c1e01..200c7b97204 100644 --- a/src/native/mono/runtime-base/internal-pinvokes.hh +++ b/src/native/mono/runtime-base/internal-pinvokes.hh @@ -3,7 +3,6 @@ #include #include -//#include #include #include From 847e385c981740c9c953d6ceeafce181b9fdc6cb Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 29 Nov 2024 10:11:56 +0100 Subject: [PATCH 021/143] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 14 +++--- .../BuildReleaseArm64XFormsDotNet.apkdesc | 45 +++++++++---------- 2 files changed, 28 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 574f95f396e..be94e0bcbf7 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 @@ -5,7 +5,7 @@ "Size": 3036 }, "classes.dex": { - "Size": 389632 + "Size": 22444 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { "Size": 18296 @@ -14,10 +14,10 @@ "Size": 86352 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 116768 + "Size": 116920 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22416 + "Size": 22408 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24376 @@ -44,7 +44,7 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 903032 + "Size": 1501240 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3196512 @@ -62,10 +62,10 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 13016 + "Size": 18264 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { "Size": 3266 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 2984469 + "PackageSize": 3111445 } \ 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 3811dba9c93..b3173a6f72f 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 @@ -5,10 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9448880 - }, - "classes2.dex": { - "Size": 154180 + "Size": 9172764 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -35,16 +32,16 @@ "Size": 19544 }, "lib/arm64-v8a/lib_FormsViewGroup.dll.so": { - "Size": 25184 + "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { "Size": 94736 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 522832 + "Size": 524256 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22416 + "Size": 22408 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21448 @@ -173,31 +170,31 @@ "Size": 22096 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { - "Size": 34760 + "Size": 34960 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.AppCompatResources.dll.so": { - "Size": 24296 + "Size": 24512 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.dll.so": { - "Size": 163072 + "Size": 163240 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CardView.dll.so": { "Size": 24560 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CoordinatorLayout.dll.so": { - "Size": 35680 + "Size": 35912 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Core.dll.so": { - "Size": 151216 + "Size": 151408 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CursorAdapter.dll.so": { "Size": 27168 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.DrawerLayout.dll.so": { - "Size": 33760 + "Size": 33944 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Fragment.dll.so": { - "Size": 72224 + "Size": 72528 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Legacy.Support.Core.UI.dll.so": { "Size": 23896 @@ -215,16 +212,16 @@ "Size": 31592 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.RecyclerView.dll.so": { - "Size": 111896 + "Size": 112248 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SavedState.dll.so": { "Size": 23144 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SwipeRefreshLayout.dll.so": { - "Size": 31672 + "Size": 31952 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager.dll.so": { - "Size": 37752 + "Size": 38048 }, "lib/arm64-v8a/lib_Xamarin.Forms.Core.dll.so": { "Size": 581000 @@ -239,7 +236,7 @@ "Size": 80632 }, "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { - "Size": 84400 + "Size": 84768 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 18832 @@ -248,7 +245,7 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 903032 + "Size": 1501240 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3196512 @@ -266,7 +263,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 120016 + "Size": 349440 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -419,10 +416,10 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { - "Size": 98661 + "Size": 98577 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -449,7 +446,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98534 + "Size": 98450 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2489,5 +2486,5 @@ "Size": 812848 } }, - "PackageSize": 10796357 + "PackageSize": 10947851 } \ No newline at end of file From c63300a838b0aaf9b99ed0c16288d5a387a3286a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 29 Nov 2024 18:10:25 +0100 Subject: [PATCH 022/143] std::format doesn't like null pointers when printing strings --- src/native/mono/monodroid/debug.cc | 22 +- .../mono/monodroid/embedded-assemblies-zip.cc | 23 ++- .../mono/monodroid/embedded-assemblies.cc | 194 +++++++++++++----- .../mono/monodroid/embedded-assemblies.hh | 4 +- .../mono/monodroid/mono-image-loader.hh | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 40 ++-- src/native/mono/monodroid/osbridge.cc | 49 ++--- .../monodroid/xamarin-android-app-context.cc | 10 +- .../mono/monodroid/xamarin_getifaddrs.cc | 8 +- .../pinvoke-override-api-impl.hh | 8 +- .../mono/pinvoke-override/precompiled.cc | 15 +- src/native/mono/runtime-base/logger.cc | 18 +- .../debug-app-helper.cc | 26 +-- 13 files changed, 257 insertions(+), 162 deletions(-) diff --git a/src/native/mono/monodroid/debug.cc b/src/native/mono/monodroid/debug.cc index e72b7aa19a6..492e114704b 100644 --- a/src/native/mono/monodroid/debug.cc +++ b/src/native/mono/monodroid/debug.cc @@ -96,8 +96,8 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (!found) log_warn (LOG_DEFAULT, "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", - mname.get (), - libname.get () + optional_string (mname.get ()), + optional_string (libname.get ()) ); } @@ -109,7 +109,7 @@ bool Debug::load_profiler (void *handle, const char *desc, const char *symbol) { ProfilerInitializer func = reinterpret_cast (java_interop_lib_symbol (handle, symbol, nullptr)); - log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func)); + log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", optional_string (symbol), reinterpret_cast(func)); if (func != nullptr) { func (desc); @@ -139,7 +139,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, "Connection options: '{}'", options); + log_info (LOG_DEFAULT, "Connection options: '{}'", optional_string (options)); args = Util::monodroid_strsplit (options, ",", 0); @@ -163,7 +163,7 @@ Debug::parse_options (char *options, ConnOptions *opts) if ((endp == arg) || (*endp != '\0')) log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, "Unknown connection option: '{}'", arg); + log_info (LOG_DEFAULT, "Unknown connection option: '{}'", optional_string (arg)); } } } @@ -275,7 +275,7 @@ Debug::process_connection (int fd) // null-terminate command [cmd_len] = 0; - log_info (LOG_DEFAULT, "Received cmd: '{}'.", command); + log_info (LOG_DEFAULT, "Received cmd: '{}'.", optional_string (command)); if (process_cmd (fd, command)) return true; @@ -487,7 +487,7 @@ Debug::process_cmd (int fd, char *cmd) profiler_fd = fd; profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { - log_error (LOG_DEFAULT, "Unknown profiler: '{}'", prof); + log_error (LOG_DEFAULT, "Unknown profiler: '{}'", optional_string (prof)); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -496,7 +496,7 @@ Debug::process_cmd (int fd, char *cmd) pthread_mutex_unlock (&process_cmd_mutex); return use_fd; } else { - log_error (LOG_DEFAULT, "Unsupported command: '{}'", cmd); + log_error (LOG_DEFAULT, "Unsupported command: '{}'", optional_string (cmd)); } return false; @@ -526,7 +526,7 @@ Debug::start_debugging (void) // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); if (enable_soft_breakpoints ()) { constexpr std::string_view soft_breakpoints { "--soft-breakpoints" }; @@ -588,10 +588,10 @@ Debug::enable_soft_breakpoints (void) bool ret; if (strcmp ("0", value) == 0) { ret = false; - log_info (LOG_DEBUGGER, "soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); + log_info (LOG_DEBUGGER, "soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); } else { ret = true; - log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); + log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); } delete[] value; return ret; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index e0cf5548a5d..2cb51ec75e2 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -22,7 +22,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector LOG_ASSEMBLY, std::format ( "Assembly store '{}' is not a valid .NET for Android assembly store file", - entry_name.get () + optional_string (entry_name.get ()) ) ); } @@ -232,7 +237,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string LOG_ASSEMBLY, std::format ( "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", - entry_name.get (), + optional_string (entry_name.get ()), header->version, ASSEMBLY_STORE_FORMAT_VERSION ) @@ -299,9 +304,9 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& log_debug ( LOG_ASSEMBLY, "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", - entry_name.get (), + optional_string (entry_name.get ()), number_of_zip_dso_entries, - name, + optional_string (name), apk_entry->name_hash, apk_entry->offset ); @@ -408,7 +413,9 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", - entry.file_name, entry.name, entry.data_size + optional_string (entry.file_name), + optional_string (entry.name), + entry.data_size ); } diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 269bf682783..95582ce2cc6 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -124,13 +124,13 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!", - name, + optional_string (name), cad.uncompressed_file_size, header->uncompressed_length ) ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name); + log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", optional_string (name)); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -143,7 +143,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} failed with code {}", - name, + optional_string (name), ret ) ); @@ -154,7 +154,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} yielded a different size (expected {}, got {})", - name, + optional_string (name), cad.uncompressed_file_size, static_cast(ret) ) @@ -228,7 +228,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", file.name); + log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", optional_string (file.name)); munmap (map_info.area, file.data_size); map_info.area = nullptr; } @@ -250,8 +250,8 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc static_cast(file.data), pointer_add (file.data, file.data_size), file.data_size, - file.name, - file.name, + optional_string (file.name), + optional_string (file.name), header.data () ); } @@ -287,7 +287,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (strcmp (assembly.name, abi_name.get ()) != 0) { return nullptr; } else { - log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", abi_name.get ()); + log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", optional_string (abi_name.get ())); } } @@ -321,7 +321,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (debug_file.data != nullptr) { if (debug_file.data_size > std::numeric_limits::max ()) { - log_warn (LOG_ASSEMBLY, std::format ("Debug info file '{}' is too big for Mono to consume", debug_file.name)); + log_warn (LOG_ASSEMBLY, "Debug info file '{}' is too big for Mono to consume", optional_string (debug_file.name)); } else { mono_debug_open_image_from_memory (image, reinterpret_cast(debug_file.data), static_cast(debug_file.data_size)); } @@ -333,7 +333,7 @@ EmbeddedAssemblies::load_bundled_assembly ( MonoImageOpenStatus status; MonoAssembly *a = mono_assembly_load_from_full (image, name.get (), &status, ref_only); if (a == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", name.get (), mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (name.get ()), optional_string (mono_image_strerror (status))); return nullptr; } @@ -348,7 +348,7 @@ EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_strin name.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ()); + log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", optional_string (name.get ())); dynamic_local_string abi_name; abi_name @@ -395,11 +395,11 @@ template EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { hash_t name_hash = xxhash::hash (name.get (), name.length ()); - log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash); + log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", optional_string (name.get ()), name_hash); const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Assembly '{}' (hash {:x}) not found", name.get (), name_hash)); + log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.get ()), name_hash); return nullptr; } @@ -436,7 +436,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_stringdata_size, assembly_runtime_info.descriptor->debug_data_size, assembly_runtime_info.descriptor->config_data_size, - name.get () + optional_string (name.get ()) ); } @@ -446,7 +446,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string(managed_type_name), nullptr); if (type == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ()); + log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", optional_string (managed_type_name), java_type_name.get ()); return nullptr; } 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 '{}'", managed_type_name); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '{}'", optional_string (managed_type_name)); return nullptr; } @@ -676,14 +676,14 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java module->image = mono_image_loaded (module->assembly_name); if (module->image == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name); + log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", optional_string (module->assembly_name)); // Fake a request from MonoVM to load the assembly. MonoAssemblyName *assembly_name = mono_assembly_name_new (module->assembly_name); MonoAssembly *assm; if (assembly_name == nullptr) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to create Mono assembly name for '{}'", module->assembly_name)); + log_error (LOG_ASSEMBLY, "typemap: failed to create Mono assembly name for '{}'", optional_string (module->assembly_name)); assm = nullptr; } else { MonoAssemblyLoadContextGCHandle alc_gchandle = mono_alc_get_default_gchandle (); @@ -692,14 +692,14 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (assm == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("typemap: failed to load managed assembly '{}'", module->assembly_name)); + log_warn (LOG_ASSEMBLY, "typemap: failed to load managed assembly '{}'", optional_string (module->assembly_name)); } else { module->image = mono_assembly_get_image (assm); } } if (module->image == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ()); + log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", optional_string (module->assembly_name), to_utf8 (java_type_name).get ()); return nullptr; } } @@ -707,7 +707,13 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java log_debug (LOG_ASSEMBLY, "typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); MonoClass *klass = mono_class_get (module->image, java_entry->type_token_id); if (klass == nullptr) [[unlikely]] { - log_error (LOG_ASSEMBLY, "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); + log_error ( + LOG_ASSEMBLY, + "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", + java_entry->type_token_id, + optional_string (module->assembly_name), + to_utf8 (java_type_name).get () + ); return nullptr; } @@ -718,7 +724,12 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java MonoReflectionType *ret = mono_type_get_object (domain, mono_class_get_type (klass)); if (ret == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); + log_warn (LOG_ASSEMBLY, + "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", + java_entry->type_token_id, + optional_string (module->assembly_name), + to_utf8 (java_type_name).get () + ); return nullptr; } @@ -783,7 +794,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapEntry *entry = typemap_managed_to_java (full_name.get ()); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ()); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", optional_string (full_name.get ())); return nullptr; } @@ -815,7 +826,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapModuleEntry *entry = match->map != nullptr ? binary_search (token, match->map, match->entry_count) : nullptr; if (entry == nullptr) { if (match->map == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ())); + log_warn (LOG_ASSEMBLY, "typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ()); return nullptr; } @@ -831,13 +842,30 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index); + log_warn ( + LOG_ASSEMBLY, + "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", + token, + token, + MonoGuidString (mvid).get (), + optional_string (match->assembly_name), + entry->java_map_index + ); return nullptr; } TypeMapJava const& java_entry = map_java[entry->java_map_index]; if (java_entry.java_name_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index); + log_warn ( + LOG_ASSEMBLY, + "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", + token, + token, + MonoGuidString (mvid).get (), + optional_string (match->assembly_name), + entry->java_map_index, + java_entry.java_name_index + ); return nullptr; } const char *ret = java_type_names[java_entry.java_name_index]; @@ -852,7 +880,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo token, token, MonoGuidString (mvid).get (), - match->assembly_name, + optional_string (match->assembly_name), ret ); @@ -923,7 +951,7 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons pointer_add (file_info.area, file_info.size), file_info.size, fd, - filename + optional_string (filename) ); return file_info; @@ -939,11 +967,11 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro LOG_ASSEMBLY, std::format ( "ERROR: Unable to load application package {}.", - apk + optional_string (apk) ) ); } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", apk, fd); + log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk), fd); zip_load_entries (fd, apk, should_register); } @@ -970,40 +998,90 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char struct stat sbuf; int res = fstatat (dir_fd, file_path, &sbuf, 0); if (res < 0) { - log_error (LOG_ASSEMBLY, "typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to stat {} file '{}/{}': {}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); return false; } file_size = static_cast(sbuf.st_size); if (file_size < sizeof (header)) { - log_error (LOG_ASSEMBLY, "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header)); + log_error ( + LOG_ASSEMBLY, + "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + sizeof (header) + ); return false; } fd = openat (dir_fd, file_path, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, "typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to open {} file {}/{} for reading: {}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); return false; } ssize_t nread = do_read (fd, &header, sizeof (header)); if (nread <= 0) { if (nread < 0) { - log_error (LOG_ASSEMBLY, "typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to read {} file header from '{}/{}': {}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); } else { - log_error (LOG_ASSEMBLY, "typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path); + log_error ( + LOG_ASSEMBLY, + "typemap: end of file while reading {} file header from '{}/{}'", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path) + ); } return false; } if (header.magic != expected_magic) { - log_error (LOG_ASSEMBLY, "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic); + log_error ( + LOG_ASSEMBLY, + "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + expected_magic, + header.magic + ); return false; } if (header.version != MODULE_FORMAT_VERSION) { - log_error (LOG_ASSEMBLY, "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version); + log_error ( + LOG_ASSEMBLY, + "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", + optional_string (file_type), + MODULE_FORMAT_VERSION, + optional_string (dir_path), + optional_string (file_path), + header.version + ); return false; } @@ -1039,7 +1117,7 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ std::unique_ptr EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", dir_path, index_path); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", optional_string (dir_path), optional_string (index_path)); TypeMapIndexHeader header; size_t file_size; @@ -1066,7 +1144,13 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * ssize_t nread = do_read (file_fd, module.assembly_name, header.assembly_name_length); if (nread != static_cast(header.assembly_name_length)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to read map assembly name from '{}/{}': {}", + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); return false; } @@ -1076,13 +1160,13 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", - dir_path, - file_path, + optional_string (dir_path), + optional_string (file_path), header.entry_count, header.java_name_width, header.managed_name_width, header.assembly_name_length, - module.assembly_name + optional_string (module.assembly_name) ); // [name][index] @@ -1096,7 +1180,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * module.data = new uint8_t [data_size]; nread = do_read (file_fd, module.data, data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno)); + log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", optional_string (dir_path), optional_string (file_path), strerror (errno)); return false; } @@ -1140,7 +1224,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * bool EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMap &module) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", dir_path, file_path); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", optional_string (dir_path), optional_string (file_path)); bool ret = true; BinaryTypeMapHeader header; @@ -1179,7 +1263,7 @@ EmbeddedAssemblies::register_from_apk (const char *apk_file, monodroid_should_re gather_bundled_assemblies_from_apk (apk_file, should_register); - log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev); + log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", optional_string (apk_file), number_of_found_assemblies - prev); return number_of_found_assemblies; } @@ -1283,10 +1367,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( [[gnu::always_inline]] size_t EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look_for_mangled_names, monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", lib_dir_path); + log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", optional_string (lib_dir_path)); DIR *lib_dir = opendir (lib_dir_path); // TODO: put it in a scope guard at some point if (lib_dir == nullptr) { - log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); return 0; } @@ -1295,14 +1379,14 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); closedir (lib_dir); return 0; } state.file_fd = dup (dir_fd); if (state.file_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, optional_string (lib_dir_path), std::strerror (errno)); closedir (lib_dir); return 0; } @@ -1319,7 +1403,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); continue; // keep going, no harm } break; // No more entries, we're done @@ -1339,7 +1423,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look // ...and we can handle the runtime config entry if (!runtime_config_blob_found && std::strncmp (cur->d_name, SharedConstants::RUNTIME_CONFIG_BLOB_NAME.data (), SharedConstants::RUNTIME_CONFIG_BLOB_NAME.size ()) == 0) { - log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", cur->d_name); + log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", optional_string (cur->d_name)); auto file_size = Util::get_file_size_at (state.file_fd, cur->d_name); if (!file_size) { continue; diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index a505721bf23..bbb91157b10 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -310,7 +310,7 @@ namespace xamarin::android::internal { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", file_name); + log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", optional_string (file_name)); // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } @@ -436,7 +436,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", name.get ()); + log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", optional_string (name.get ())); }; private: diff --git a/src/native/mono/monodroid/mono-image-loader.hh b/src/native/mono/monodroid/mono-image-loader.hh index e8211259ca9..ac33fe53588 100644 --- a/src/native/mono/monodroid/mono-image-loader.hh +++ b/src/native/mono/monodroid/mono-image-loader.hh @@ -110,7 +110,7 @@ namespace xamarin::android::internal { force_inline static MonoImage* stash_and_return (MonoImage *image, MonoImageOpenStatus status, [[maybe_unused]] hash_t hash) noexcept { if (image == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to open assembly image. {}", mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to open assembly image. {}", optional_string (mono_image_strerror (status))); return nullptr; } diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index c01f45dabd1..135c296a61a 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -174,12 +174,12 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] fullpath.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", fullpath.get ()); + log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", optional_string (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) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status)); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (fullpath.get ()), mono_image_strerror (status)); } } else { log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); @@ -480,7 +480,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string arg (token); - log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", arg.get ()); + log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", optional_string (arg.get ())); ret = false; } } @@ -509,7 +509,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse cur_time = time (nullptr); if (!parse_runtime_args (runtime_args, &options)) { - log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", runtime_args.get ()); + log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", optional_string (runtime_args.get ())); } else if (options.debug && cur_time > options.timeout_time) { log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time); } else if (options.debug && cur_time <= options.timeout_time) { @@ -537,7 +537,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); if (options.out_port > 0) { int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -576,7 +576,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse LOG_DEBUGGER, std::format ( "Error accepting stdout and stderr ({}:{}): {}", - options.host, + optional_string (options.host), options.out_port, strerror (errno) ) @@ -591,7 +591,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse LOG_DEBUGGER, std::format ( "Error connecting stdout and stderr ({}:{}): {}", - options.host, + optional_string (options.host), options.out_port, strerror (errno) ) @@ -662,7 +662,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; - log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", prop_val.get ()); + log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", optional_string (prop_val.get ())); char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; @@ -731,8 +731,8 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks #if defined (DEBUG) log_fatal (LOG_DEFAULT, "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", - AndroidSystem::override_dirs [0], - (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv + optional_string (AndroidSystem::override_dirs [0]), + (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? optional_string (AndroidSystem::override_dirs [1]) : "" ); #else log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"sv); @@ -741,7 +741,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks Helpers::abort_application ( std::format ( "ALL entries in APK named `{}` MUST be STORED. Gradle's minification may COMPRESS such entries.", - assemblies_prefix + optional_string (assemblies_prefix) ) ); } @@ -943,7 +943,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec auto initialize = reinterpret_cast (mono_method_get_unmanaged_callers_only_ftnptr (method, &error)); if (initialize == nullptr) { - log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error)); + log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", optional_string (mono_error_get_message (&error))); } abort_unless ( @@ -999,7 +999,7 @@ MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstr if (createDirectory) { 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 {}. {}", name, strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory for environment variable {}. {}", optional_string (name), strerror (errno)); } setenv (name, value.get_cstr (), 1); } @@ -1009,10 +1009,10 @@ MonodroidRuntime::create_xdg_directory (jstring_wrapper& home, size_t home_len, { static_local_string dir (home_len + 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: {}", dir.get ()); + log_debug (LOG_DEFAULT, "Creating XDG directory: {}", optional_string (dir.get ())); int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", dir.get (), strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", optional_string (dir.get ()), strerror (errno)); if (!environment_variable_name.empty ()) { setenv (environment_variable_name.data (), dir.get (), 1); } @@ -1041,7 +1041,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", name, v); + log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", optional_string (name), optional_string (v)); }; string_segment arg_token; @@ -1061,7 +1061,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept log_envvar (arg.get (), one.data ()); } else if (index == 0) { // ’=value’ - log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", arg.get ()); + log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", optional_string (arg.get ())); } else { // ’name=value’ arg[index] = '\0'; @@ -1141,10 +1141,10 @@ MonodroidRuntime::set_profile_options () noexcept .append (output_path.get (), output_path.length ()); } if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); } - log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", value.get ()); + log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", optional_string (value.get ())); debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } @@ -1469,7 +1469,7 @@ 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: {}", AndroidSystem::get_runtime_libdir ()); + log_debug (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); } AndroidSystem::setup_process_args (runtimeApks); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 727e277d501..919506d3fda 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -186,7 +186,7 @@ OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) *end = '\0'; if ((category == LOG_GREF && gref_to_logcat) || (category == LOG_LREF && lref_to_logcat)) { - log_debug (category, "{}", m); + log_debug (category, "{}", optional_string (m)); } if (to != nullptr) { fprintf (to, "%s\n", optional_string (m)); @@ -200,7 +200,7 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, "{}", message); + log_debug (LOG_GREF, "{}", optional_string (message)); } if (!gref_log) return; @@ -214,6 +214,7 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH int c = _monodroid_gref_inc (); if ((log_categories & LOG_GREF) == 0) return c; + log_info (LOG_GREF, "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", c, @@ -222,14 +223,14 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH curType, reinterpret_cast(newHandle), newType, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -265,14 +266,14 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr gc_weak_gref_count, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -306,14 +307,14 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new curType, reinterpret_cast(newHandle), newType, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -347,14 +348,14 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th gc_weak_gref_count, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -384,14 +385,14 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c lrefc, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!lref_log) @@ -420,14 +421,14 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons lrefc, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!lref_log) @@ -541,8 +542,8 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) if (i == static_cast (-NUM_GC_BRIDGE_TYPES)) { log_info (LOG_GC, "asked if a class {}.{} is a bridge before we inited java.lang.Object", - mono_class_get_namespace (klass), - mono_class_get_name (klass) + optional_string (mono_class_get_namespace (klass)), + optional_string (mono_class_get_name (klass)) ); return MonoGCBridgeObjectKind::GC_BRIDGE_TRANSPARENT_CLASS; } @@ -569,8 +570,8 @@ OSBridge::gc_is_bridge_object (MonoObject *object) MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, "object of class {}.{} with null handle", - mono_class_get_namespace (mclass), - mono_class_get_name (mclass) + optional_string (mono_class_get_namespace (mclass)), + optional_string (mono_class_get_name (mclass)) ); #endif return 0; @@ -657,9 +658,9 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri *reffed_description = describe_target (reffed_target); if (success) - log_warn (LOG_GC, "Added reference for {} to {}", description, reffed_description); + log_warn (LOG_GC, "Added reference for {} to {}", optional_string (description), optional_string (reffed_description)); else - log_error (LOG_GC, "Missing monodroidAddReference method for {}", description); + log_error (LOG_GC, "Missing monodroidAddReference method for {}", optional_string (description)); free (description); free (reffed_description); @@ -897,8 +898,8 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri klass = mono_object_get_class (obj); log_error (LOG_GC, "Missing monodroidClearReferences method for object of class {}.{}", - mono_class_get_namespace (klass), - mono_class_get_name (klass) + optional_string (mono_class_get_namespace (klass)), + optional_string (mono_class_get_name (klass)) ); } #endif @@ -963,8 +964,8 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre log_info (LOG_GC, "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", reinterpret_cast(obj), - mono_class_get_namespace (klass), - mono_class_get_name (klass), + optional_string (mono_class_get_namespace (klass)), + optional_string (mono_class_get_name (klass)), reinterpret_cast(handle), key_handle ); diff --git a/src/native/mono/monodroid/xamarin-android-app-context.cc b/src/native/mono/monodroid/xamarin-android-app-context.cc index 75973eb020e..9ef193ddeb7 100644 --- a/src/native/mono/monodroid/xamarin-android-app-context.cc +++ b/src/native/mono/monodroid/xamarin-android-app-context.cc @@ -44,8 +44,8 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, "MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", - get_method_name (mono_image_index, method_token), method_token, - get_class_name (class_index), class_index + optional_string (get_method_name (mono_image_index, method_token)), method_token, + optional_string (get_class_name (class_index)), class_index ); if (class_index >= marshal_methods_number_of_classes) [[unlikely]] { @@ -81,7 +81,7 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, "Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", - mono_method_full_name (method, true), + optional_string (mono_method_full_name (method, true)), ret, mono_image_index, class_index, @@ -93,8 +93,8 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_fatal ( LOG_DEFAULT, "Failed to obtain function pointer to method '{}' in class '{}'", - get_method_name (mono_image_index, method_token), - get_class_name (class_index) + optional_string (get_method_name (mono_image_index, method_token)), + optional_string (get_class_name (class_index)) ); log_fatal ( diff --git a/src/native/mono/monodroid/xamarin_getifaddrs.cc b/src/native/mono/monodroid/xamarin_getifaddrs.cc index 57c4935a7bf..23848f9910b 100644 --- a/src/native/mono/monodroid/xamarin_getifaddrs.cc +++ b/src/native/mono/monodroid/xamarin_getifaddrs.cc @@ -962,7 +962,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " address has no name/label, getting one from interface"sv); ifa->ifa_name = name ? strdup (name) : NULL; } - log_debug (LOG_NETLINK, " address label: {}", ifa->ifa_name); + log_debug (LOG_NETLINK, " address label: {}", optional_string (ifa->ifa_name)); if (calculate_address_netmask (ifa, net_address) < 0) { goto error; @@ -1017,7 +1017,7 @@ get_link_info (const struct nlmsghdr *message) } if (Util::should_log (LOG_NETLINK)) { log_debug_nocheck_fmt (LOG_NETLINK, " interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); - log_debug_nocheck_fmt (LOG_NETLINK, " {}", ifa->ifa_name); + log_debug_nocheck_fmt (LOG_NETLINK, " {}", optional_string (ifa->ifa_name)); } break; @@ -1150,7 +1150,7 @@ print_ifla_name (int id) i++; continue; } - log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", iflas [i].name, iflas [i].value); + log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", optional_string (iflas [i].name), iflas [i].value); break; } } @@ -1180,7 +1180,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) cur = cur->ifa_next; } - log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, msg ? msg : "[no addresses]"sv); + log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, optional_string (msg, "[no addresses]")); free (msg); } #endif diff --git a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh index f6c402c46e7..259a0d5c879 100644 --- a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh @@ -23,21 +23,21 @@ namespace xamarin::android { constexpr bool PREFER_AOT_CACHE = false; lib_handle = internal::MonodroidDl::monodroid_dlopen (library_name, MONO_DL_LOCAL, nullptr, PREFER_AOT_CACHE); if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name); + log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", optional_string (library_name), optional_string (symbol_name)); return nullptr; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", library_name); + log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", optional_string (library_name)); } } } void *entry_handle = internal::MonodroidDl::monodroid_dlsym (lib_handle, symbol_name, nullptr, nullptr); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name); + log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", optional_string (library_name), optional_string (symbol_name)); return nullptr; } @@ -147,7 +147,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", library_name); + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", optional_string (library_name)); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index e5c54608ff3..29ac736e433 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -22,18 +22,19 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash); + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", + optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash); + log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", optional_string (e.name), e.func, e.hash); } Helpers::abort_application ( LOG_ASSEMBLY, std::format ( "Failure handling a p/invoke request for '{}'@'{}'", - entrypoint_name, - library_name + optional_string (entrypoint_name), + optional_string (library_name) ) ); } @@ -67,7 +68,8 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name); + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", + optional_string (entrypoint_name), optional_string (library_name)); return nullptr; // let Mono deal with the fallout } @@ -75,7 +77,8 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha } // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below - log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name); + log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", + optional_string (entrypoint_name), optional_string (library_name)); } return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); diff --git a/src/native/mono/runtime-base/logger.cc b/src/native/mono/runtime-base/logger.cc index de5f6dee5cf..92c3137cd7a 100644 --- a/src/native/mono/runtime-base/logger.cc +++ b/src/native/mono/runtime-base/logger.cc @@ -29,13 +29,11 @@ namespace { if (path && access (path, W_OK) < 0) { log_warn (category, - std::format ( - "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", - path, - strerror (errno), - override_dir, - filename - ) + "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", + optional_string (path), + strerror (errno), + optional_string (override_dir), + optional_string (filename) ); path = NULL; } @@ -53,7 +51,7 @@ namespace { if (f) { Util::set_world_accessable (path); } else { - log_warn (category, std::format ("Could not open path '{}' for logging: {}", path, strerror (errno))); + log_warn (category, "Could not open path '{}' for logging: {}", optional_string (path), strerror (errno)); } free (p); @@ -79,12 +77,12 @@ Logger::set_debugger_log_level (const char *level) noexcept unsigned long v = strtoul (level, nullptr, 0); if (v == std::numeric_limits::max () && errno == ERANGE) { - log_error (LOG_DEFAULT, std::format ("Invalid debugger log level value '{}', expecting a positive integer or zero", level)); + log_error (LOG_DEFAULT, "Invalid debugger log level value '{}', expecting a positive integer or zero", level); return; } if (v > std::numeric_limits::max ()) { - log_warn (LOG_DEFAULT, std::format ("Debugger log level value is higher than the maximum of {}, resetting to the maximum value.", std::numeric_limits::max ())); + log_warn (LOG_DEFAULT, "Debugger log level value is higher than the maximum of {}, resetting to the maximum value.", std::numeric_limits::max ()); v = std::numeric_limits::max (); } diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index 1d3dc1ce812..e64c42750c8 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -48,7 +48,7 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, "Using runtime path: {}", AndroidSystem::get_runtime_libdir ()); + log_warn (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); } const char *monosgen_path = get_libmonosgen_path (); @@ -75,7 +75,9 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) log_warn (LOG_DEFAULT, "Copying file `{}` from external location `{}` to internal location `{}`", - file, from_dir, to_dir + optional_string (file), + optional_string (from_dir), + optional_string (to_dir) ); to_file = Util::path_combine (to_dir, file); @@ -84,12 +86,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) int r = unlink (to_file); if (r < 0 && errno != ENOENT) { - log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", to_file, strerror (errno)); + log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", optional_string (to_file), strerror (errno)); break; } if (!Util::file_copy (to_file, from_file)) { - log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno)); + log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", optional_string (from_file), optional_string (to_file), strerror (errno)); break; } @@ -108,22 +110,22 @@ copy_native_libraries_to_internal_location () dirent *e; char *dir_path = Util::path_combine (od, "lib"); - log_warn (LOG_DEFAULT, "checking directory: `{}`", dir_path); + log_warn (LOG_DEFAULT, "checking directory: `{}`", optional_string (dir_path)); if (dir_path == nullptr || !Util::directory_exists (dir_path)) { - log_warn (LOG_DEFAULT, "directory does not exist: `{}`", dir_path); + log_warn (LOG_DEFAULT, "directory does not exist: `{}`", optional_string (dir_path)); delete[] dir_path; continue; } if ((dir = ::opendir (dir_path)) == nullptr) { - log_warn (LOG_DEFAULT, "could not open directory: `{}`", dir_path); + log_warn (LOG_DEFAULT, "could not open directory: `{}`", optional_string (dir_path)); delete[] dir_path; continue; } while ((e = readdir (dir)) != nullptr) { - log_warn (LOG_DEFAULT, "checking file: `{}`", e->d_name); + log_warn (LOG_DEFAULT, "checking file: `{}`", optional_string (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); } @@ -140,9 +142,9 @@ runtime_exists (const char *dir, char*& libmonoso) return false; libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); - log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", libmonoso); + log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", optional_string (libmonoso)); if (Util::file_exists (libmonoso)) { - log_info (LOG_DEFAULT, "Mono runtime found at: {}", libmonoso); + log_info (LOG_DEFAULT, "Mono runtime found at: {}", optional_string (libmonoso)); return true; } delete[] libmonoso; @@ -194,7 +196,7 @@ get_libmonosgen_path () if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { - log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", link, libmonoso); + log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", optional_string (link), optional_string (libmonoso)); unlink (link); result = symlink (libmonoso, link); } @@ -205,7 +207,7 @@ get_libmonosgen_path () libmonoso = link; } - log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv); + log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", optional_string (libmonoso)); if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; From 3b87eb991007ef9d21efe27c8bf48b68e74d092b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 2 Dec 2024 22:15:16 +0100 Subject: [PATCH 023/143] Beginnings of CLR hosting --- Xamarin.Android.sln | 12 +- .../xaprepare/ConfigAndData/Configurables.cs | 1 + .../xaprepare/Steps/Step_GenerateFiles.cs | 18 +- src/native-clr/.gitignore | 2 + src/native-clr/CMakeLists.txt | 517 ++++++++++ src/native-clr/CMakePresets.json.in | 324 ++++++ src/native-clr/host/CMakeLists.txt | 155 +++ src/native-clr/host/host-jni.cc | 43 + src/native-clr/host/host.cc | 11 + src/native-clr/include/constants.hh | 96 ++ src/native-clr/include/host/host-jni.hh | 48 + src/native-clr/include/host/host.hh | 13 + .../include/runtime-base/android-system.hh | 39 + .../include/runtime-base/strings.hh | 920 ++++++++++++++++++ src/native-clr/include/shared/cpp-util.hh | 212 ++++ src/native-clr/include/shared/helpers.hh | 105 ++ src/native-clr/include/shared/log_level.hh | 26 + src/native-clr/include/shared/log_types.hh | 112 +++ src/native-clr/include/shared/xxhash.hh | 192 ++++ src/native-clr/include/startup/zip.hh | 31 + src/native-clr/include/xamarin-app.hh | 380 ++++++++ src/native-clr/java-interop/CMakeLists.txt | 50 + src/native-clr/libnet-android.map.txt | 12 + src/native-clr/lz4/CMakeLists.txt | 41 + src/native-clr/native-clr.csproj | 22 + src/native-clr/native-clr.targets | 144 +++ src/native-clr/runtime-base/CMakeLists.txt | 55 ++ src/native-clr/runtime-base/android-system.cc | 134 +++ src/native-clr/shared/CMakeLists.txt | 59 ++ src/native-clr/shared/helpers.cc | 46 + src/native-clr/shared/log_functions.cc | 131 +++ src/native-clr/startup/CMakeLists.txt | 52 + src/native-clr/startup/zip.cc | 3 + .../xamarin-app-stub/CMakeLists.txt | 54 + .../xamarin-app-stub/application_dso_stub.cc | 297 ++++++ 35 files changed, 4348 insertions(+), 9 deletions(-) create mode 100644 src/native-clr/.gitignore create mode 100644 src/native-clr/CMakeLists.txt create mode 100644 src/native-clr/CMakePresets.json.in create mode 100644 src/native-clr/host/CMakeLists.txt create mode 100644 src/native-clr/host/host-jni.cc create mode 100644 src/native-clr/host/host.cc create mode 100644 src/native-clr/include/constants.hh create mode 100644 src/native-clr/include/host/host-jni.hh create mode 100644 src/native-clr/include/host/host.hh create mode 100644 src/native-clr/include/runtime-base/android-system.hh create mode 100644 src/native-clr/include/runtime-base/strings.hh create mode 100644 src/native-clr/include/shared/cpp-util.hh create mode 100644 src/native-clr/include/shared/helpers.hh create mode 100644 src/native-clr/include/shared/log_level.hh create mode 100644 src/native-clr/include/shared/log_types.hh create mode 100644 src/native-clr/include/shared/xxhash.hh create mode 100644 src/native-clr/include/startup/zip.hh create mode 100644 src/native-clr/include/xamarin-app.hh create mode 100644 src/native-clr/java-interop/CMakeLists.txt create mode 100644 src/native-clr/libnet-android.map.txt create mode 100644 src/native-clr/lz4/CMakeLists.txt create mode 100644 src/native-clr/native-clr.csproj create mode 100644 src/native-clr/native-clr.targets create mode 100644 src/native-clr/runtime-base/CMakeLists.txt create mode 100644 src/native-clr/runtime-base/android-system.cc create mode 100644 src/native-clr/shared/CMakeLists.txt create mode 100644 src/native-clr/shared/helpers.cc create mode 100644 src/native-clr/shared/log_functions.cc create mode 100644 src/native-clr/startup/CMakeLists.txt create mode 100644 src/native-clr/startup/zip.cc create mode 100644 src/native-clr/xamarin-app-stub/CMakeLists.txt create mode 100644 src/native-clr/xamarin-app-stub/application_dso_stub.cc diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index 782b20c69db..936ba23b285 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -125,7 +125,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Sdk.Analy EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proguard-android", "src\proguard-android\proguard-android.csproj", "{5FD0133B-69E5-4474-9B67-9FD1D0150C70}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Runtime.NativeAOT", "src\Microsoft.Android.Runtime.NativeAOT\Microsoft.Android.Runtime.NativeAOT.csproj", "{E8831F32-11D7-D42C-E43C-711998BC357A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "native-clr", "src\native-clr\native-clr.csproj", "{AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -349,10 +349,10 @@ Global {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Debug|AnyCPU.Build.0 = Debug|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.ActiveCfg = Release|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.Build.0 = Release|Any CPU - {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU - {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.Build.0 = Debug|Any CPU - {E8831F32-11D7-D42C-E43C-711998BC357A}.Release|AnyCPU.ActiveCfg = Release|Any CPU - {E8831F32-11D7-D42C-E43C-711998BC357A}.Release|AnyCPU.Build.0 = Release|Any CPU + {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU + {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Debug|AnyCPU.Build.0 = Debug|Any CPU + {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Release|AnyCPU.ActiveCfg = Release|Any CPU + {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Release|AnyCPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -412,7 +412,7 @@ Global {A39B6D7C-6616-40D6-8AE4-C6CEE93D2708} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {5E806C9F-1B67-4B6B-A6AB-258834250DBB} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} {5FD0133B-69E5-4474-9B67-9FD1D0150C70} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} - {E8831F32-11D7-D42C-E43C-711998BC357A} = {04E3E11E-B47D-4599-8AFC-50515A95E715} + {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6} diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 9c77341f969..01aefb637e4 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -176,6 +176,7 @@ public static partial class Paths 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"); + public static readonly string NativeCLRSourcesDir = Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "src", "native-clr"); // 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 af3c6cac1b6..e7a48b4e4c0 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -58,6 +58,7 @@ protected override async Task Execute (Context context) Get_Configuration_Generated_Props (context), Get_Cmake_XA_Build_Configuration (context), Get_Cmake_Presets (context), + Get_Cmake_Presets_CLR (context), }; } else { return new List { @@ -66,6 +67,7 @@ protected override async Task Execute (Context context) Get_Configuration_Generated_Props (context), Get_Cmake_XA_Build_Configuration (context), Get_Cmake_Presets (context), + Get_Cmake_Presets_CLR (context), Get_Ndk_projitems (context), Get_XABuildConfig_cs (context), Get_Omnisharp_Json (context), @@ -107,7 +109,7 @@ GeneratedFile Get_Cmake_XA_Build_Configuration (Context context) ); } - GeneratedFile Get_Cmake_Presets (Context context) + GeneratedFile GetCmakePresetsCommon (Context context, string sourcesDir) { const string OutputFileName = "CMakePresets.json"; @@ -126,11 +128,21 @@ GeneratedFile Get_Cmake_Presets (Context context) return new GeneratedPlaceholdersFile ( replacements, - Path.Combine (Configurables.Paths.NativeSourcesDir, $"{OutputFileName}.in"), - Path.Combine (Configurables.Paths.NativeSourcesDir, OutputFileName) + Path.Combine (sourcesDir, $"{OutputFileName}.in"), + Path.Combine (sourcesDir, OutputFileName) ); } + GeneratedFile Get_Cmake_Presets (Context context) + { + return GetCmakePresetsCommon (context, Configurables.Paths.NativeSourcesDir); + } + + GeneratedFile Get_Cmake_Presets_CLR (Context context) + { + return GetCmakePresetsCommon (context, Configurables.Paths.NativeCLRSourcesDir); + } + GeneratedFile Get_Configuration_Generated_Props (Context context) { const string OutputFileName = "Configuration.Generated.props"; diff --git a/src/native-clr/.gitignore b/src/native-clr/.gitignore new file mode 100644 index 00000000000..34d21e62347 --- /dev/null +++ b/src/native-clr/.gitignore @@ -0,0 +1,2 @@ +CMakeUserPresets.json +CMakePresets.json diff --git a/src/native-clr/CMakeLists.txt b/src/native-clr/CMakeLists.txt new file mode 100644 index 00000000000..3f2a4c627a0 --- /dev/null +++ b/src/native-clr/CMakeLists.txt @@ -0,0 +1,517 @@ +cmake_minimum_required(VERSION 3.21) + +# +# Read product version +# +file(STRINGS "../../Directory.Build.props" XA_PRODUCT_VERSION_XML REGEX "^[ \t]*(.*)") +string(REGEX REPLACE "^[ \t]*(.*)" "\\1" XA_VERSION "${XA_PRODUCT_VERSION_XML}") + +project( + android-native-bits + VERSION ${XA_VERSION} + DESCRIPTION ".NET for Android native runtime" + HOMEPAGE_URL "https://github.com/dotnet/android" + LANGUAGES CXX C ASM +) + +# +# Sanity checks +# +macro(ensure_variable_set VARNAME) + if(NOT ${VARNAME}) + message(FATAL_ERROR "Variable ${VARNAME} not set. Please set it either on command line with -D${VARNAME}=value or in the presets file") + endif() +endmacro() + +ensure_variable_set(ANDROID_ABI) +ensure_variable_set(CMAKE_ANDROID_NDK) +ensure_variable_set(CMAKE_BUILD_TYPE) +ensure_variable_set(OUTPUT_PATH) +ensure_variable_set(XA_BUILD_CONFIGURATION) +ensure_variable_set(XA_LIB_TOP_DIR) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}" CACHE PATH "" FORCE) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}" CACHE PATH "" FORCE) + +set(CMAKE_CXX_STANDARD 23) +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") +#include("${CMAKE_SOURCE_DIR}/cmake/ArchiveDSOStub.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 AND ENABLE_CLANG_UBSAN) + message(FATAL_ERROR "Both ASAN and UBSAN builds cannot be enabled at the same time") +endif() + +if(ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) + if(BUILD_ARCHIVE_DSO_STUB) + message(FATAL_ERROR "ASAN/UBSAN builds aren't supported by the archive DSO target") + endif() + + 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(ENABLE_CLANG_ASAN) + set(STATIC_LIB_NAME_SUFFIX "-clr-asan") +elseif(ENABLE_CLANG_UBSAN) + set(STATIC_LIB_NAME_SUFFIX "-clr-ubsan") +else() + set(STATIC_LIB_NAME_SUFFIX "-clr") +endif() + +if(DEBUG_BUILD) + set(STATIC_LIB_NAME_SUFFIX "${STATIC_LIB_NAME_SUFFIX}-debug") +else() + set(STATIC_LIB_NAME_SUFFIX "${STATIC_LIB_NAME_SUFFIX}-release") +endif() + +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() + +# +# Needed modules +# +# include(CheckIncludeFile) +# include(CheckCXXSymbolExists) +include(CheckCXXCompilerFlag) +include(CheckCCompilerFlag) +include(CheckLinkerFlag) + +# +# General config +# +set(XA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Build${XA_BUILD_CONFIGURATION}") +include("${XA_BUILD_DIR}/xa_build_configuration.cmake") + +# +# Paths +# +if(ANDROID_ABI MATCHES "^arm64-v8a") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM64}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_arm64-v8a_TRIPLE}") +elseif(ANDROID_ABI MATCHES "^armeabi-v7a") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_armeabi-v7a_TRIPLE}") +elseif(ANDROID_ABI MATCHES "^x86_64") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86_64}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_x86_64_TRIPLE}") +elseif(ANDROID_ABI MATCHES "^x86") + set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86}") + set(TOOLCHAIN_TRIPLE "${NDK_ABI_x86_TRIPLE}") +else() + message(FATAL "${ANDROID_ABI} is not supported for .NET 6+ builds") +endif() + + +file(REAL_PATH "../../" REPO_ROOT_DIR) +set(EXTERNAL_DIR "${REPO_ROOT_DIR}/external") +set(JAVA_INTEROP_SRC_PATH "${EXTERNAL_DIR}/Java.Interop/src/java-interop") +#set(LIBUNWIND_SOURCE_DIR "${EXTERNAL_DIR}/libunwind") +#set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") + +# +# Include directories +# +set(SYSROOT_CXX_INCLUDE_DIR ${CMAKE_SYSROOT}/usr/include/c++/v1) +set(MONO_RUNTIME_INCLUDE_DIR ${NET_RUNTIME_DIR}/native/include/mono-2.0) +set(JAVA_INTEROP_INCLUDE_DIR ${JAVA_INTEROP_SRC_PATH}) +set(XA_RUNTIME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) +set(CONSTEXPR_XXH3_DIR ${EXTERNAL_DIR}/constexpr-xxh3) + +macro(xa_add_include_directories TARGET) + target_include_directories( + ${TARGET} + PRIVATE + ${XA_RUNTIME_INCLUDE_DIR} + ${EXTERNAL_DIR} + ${CONSTEXPR_XXH3_DIR} + ) +endmacro() + +# +# Compiler defines +# +macro(xa_add_compile_definitions TARGET) + target_compile_definitions( + ${TARGET} + PRIVATE + XA_VERSION="${XA_VERSION}" + _REENTRANT + PLATFORM_ANDROID + ) + + if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") + target_compile_definitions( + ${TARGET} + PRIVATE + ANDROID64 + ) + endif() +endmacro() + +if(NOT BUILD_ARCHIVE_DSO_STUB) + if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + add_compile_definitions(DEBUG) + endif() + + if(NOT DEBUG_BUILD) + add_compile_definitions(RELEASE NDEBUG) + endif() +endif() + +# +# Compiler argument macros +# +macro(_compiler_has_arg _lang _arg) + string(REGEX REPLACE "-|,|=" "_" _arg_name ${_arg}) + string(TOUPPER "${_lang}" _lang_upper) + + cmake_language(CALL check_${_lang}_compiler_flag "${_arg}" HAS_${_arg_name}_${_lang_upper}) + if(HAS_${_arg_name}_${_lang_upper}) + set(COMPILER_ARG_FOUND True) + else() + set(COMPILER_ARG_FOUND False) + endif() +endmacro() + +macro(cxx_compiler_has_arg _arg) + _compiler_has_arg(cxx ${_arg}) +endmacro() + +macro(c_compiler_has_arg _arg) + _compiler_has_arg(c ${_arg}) +endmacro() + +macro(_linker_has_arg _lang _arg) + string(REGEX REPLACE "-|,|=" "_" _arg_name ${_arg}) + string(TOUPPER "${_lang}" _lang_upper) + + check_linker_flag(${_lang} "${_arg}" HAS_${_arg_name}_LINKER_${_lang_upper}) + if(HAS_${_arg_name}_LINKER_${_lang_upper}) + set(LINKER_ARG_FOUND True) + else() + set(LINKER_ARG_FOUND False) + endif() +endmacro() + +macro(cxx_linker_has_arg _arg) + _linker_has_arg(CXX ${_arg}) +endmacro() + +macro(c_linker_has_arg _arg) + _linker_has_arg(C ${_arg}) +endmacro() + +macro(xa_check_c_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + c_compiler_has_arg(${arg}) + if(COMPILER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +macro(xa_check_cxx_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + cxx_compiler_has_arg(${arg}) + if(COMPILER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +macro(xa_check_c_linker_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + c_linker_has_arg(${arg}) + if(LINKER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +macro(xa_check_cxx_linker_args VARNAME _CHECK_ARGS) + set(_CHECKED_ARGS "") + + foreach(arg ${_CHECK_ARGS}) + cxx_linker_has_arg(${arg}) + if(LINKER_ARG_FOUND) + list(APPEND _CHECKED_ARGS "${arg}") + endif() + endforeach() + + set(${VARNAME} "${_CHECKED_ARGS}") +endmacro() + +set(CLANG_CHECK_SOURCES "") +macro(add_clang_check_sources SOURCES) + foreach(_source ${SOURCES}) + cmake_path(IS_RELATIVE _source _relative_path) + if(${_relative_path}) + list(APPEND _LOCAL_CLANG_CHECK_SOURCES_ ${CMAKE_CURRENT_SOURCE_DIR}/${_source}) + else() + list(APPEND _LOCAL_CLANG_CHECK_SOURCES_ ${_source}) + endif() + endforeach() + set(CLANG_CHECK_SOURCES "${_LOCAL_CLANG_CHECK_SOURCES_};${CLANG_CHECK_SOURCES}" PARENT_SCOPE) +endmacro() + +# +# Compiler args +# +set(CMAKE_CXX_VISIBILITY_PRESET "hidden") +set(CMAKE_C_VISIBILITY_PRESET "hidden") + +# +# Common flags are used when building all external +# and our own code +# +set(POTENTIAL_COMMON_COMPILER_ARGS + -fstack-protector-strong + -fstrict-return + -flto=thin + -fno-strict-aliasing + -fno-function-sections + -fno-data-sections + -funswitch-loops + -Wa,-noexecstack + -fPIC + -O2 +) + +if(NOT BUILD_ARCHIVE_DSO_STUB) + list(APPEND POTENTIAL_COMMON_COMPILER_ARGS + -g + ) +endif() + +set(POTENTIAL_COMMON_LINKER_ARGS + -fstack-protector-strong + -flto=thin + 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 + -Wno-vla-cxx-extension + -Wimplicit-fallthrough + -Wmisleading-indentation + -Wnull-dereference + -Wpointer-arith + -Wshadow + -Wsign-compare + -Wtrampolines + -Wuninitialized + -fstrict-flex-arrays=3 +) + +if (ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) + list(APPEND POTENTIAL_XA_COMMON_COMPILER_ARGS + -fno-omit-frame-pointer + -fno-optimize-sibling-calls + ) +endif() + +set(POTENTIAL_XA_DSO_LINKER_ARGS + -fpic + -fstack-clash-protection +) + +unset(SANITIZER_FLAGS) +if (ENABLE_CLANG_ASAN) + set(SANITIZER_FLAGS -fsanitize=address) + set(CHECKED_BUILD_INFIX "-checked+asan") +elseif(ENABLE_CLANG_UBSAN) + set(SANITIZER_FLAGS -fsanitize=undefined) + set(CHECKED_BUILD_INFIX "-checked+ubsan") +endif() + +if(SANITIZER_FLAGS) + message(STATUS) + message(STATUS "Got sanitizer: ${SANITIZER_FLAGS}") + message(STATUS) + + list(APPEND POTENTIAL_XA_COMMON_COMPILER_ARGS ${SANITIZER_FLAGS}) + list(APPEND POTENTIAL_XA_COMMON_LINKER_ARGS ${SANITIZER_FLAGS}) + list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${SANITIZER_FLAGS}) +endif() + +message(STATUS) +message(STATUS "Checking support for common compiler and linker args") +message(STATUS) +xa_check_cxx_args(COMMON_CXX_ARGS "${POTENTIAL_COMMON_COMPILER_ARGS}") +xa_check_c_args(COMMON_C_ARGS "${POTENTIAL_COMMON_COMPILER_ARGS}") +xa_check_cxx_linker_args(COMMON_CXX_LINKER_ARGS "${POTENTIAL_COMMON_LINKER_ARGS}") +xa_check_c_linker_args(COMMON_C_LINKER_ARGS "${POTENTIAL_COMMON_LINKER_ARGS}") + +message(STATUS) +message(STATUS "Checking support for XA common compiler and linker args") +message(STATUS) +xa_check_cxx_args(XA_COMMON_CXX_ARGS "${POTENTIAL_XA_COMMON_COMPILER_ARGS}") +xa_check_c_args(XA_COMMON_C_ARGS "${POTENTIAL_XA_COMMON_COMPILER_ARGS}") +xa_check_cxx_linker_args(XA_COMMON_CXX_LINKER_ARGS "${POTENTIAL_XA_COMMON_LINKER_ARGS}") +xa_check_c_linker_args(XA_COMMON_C_LINKER_ARGS "${POTENTIAL_XA_COMMON_LINKER_ARGS}") +xa_check_c_linker_args(XA_C_DSO_LINKER_ARGS "${POTENTIAL_XA_DSO_LINKER_ARGS}") +xa_check_cxx_linker_args(XA_CXX_DSO_LINKER_ARGS "${POTENTIAL_XA_DSO_LINKER_ARGS}") + +if(NOT BUILD_ARCHIVE_DSO_STUB) + 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}>") +endif() + +# +# Helper macros +# +macro(set_static_library_suffix TARGET_NAME) + if(STATIC_LIB_NAME_SUFFIX) + set_target_properties( + ${TARGET_NAME} + PROPERTIES + SUFFIX "${STATIC_LIB_NAME_SUFFIX}.a" + ) + endif() +endmacro() + +if(BUILD_ARCHIVE_DSO_STUB) + add_subdirectory(archive-dso-stub) +else() +# 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) +# add_subdirectory(pinvoke-override) + add_subdirectory(startup) + add_subdirectory(host) + +# if(DEBUG_BUILD) +# add_subdirectory(xamarin-debug-app-helper) +# endif() + +# add_subdirectory(monodroid) + + add_custom_target(run_static_analysis + COMMAND ${ANDROID_TOOLCHAIN_ROOT}/bin/clang-check -analyze -p="${CMAKE_CURRENT_BINARY_DIR}" ${CLANG_CHECK_SOURCES} > ${CMAKE_SOURCE_DIR}/static-analysis.${ANDROID_ABI}.${CMAKE_BUILD_TYPE}.txt 2>&1 + COMMAND_EXPAND_LISTS + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + USES_TERMINAL + ) +endif() diff --git a/src/native-clr/CMakePresets.json.in b/src/native-clr/CMakePresets.json.in new file mode 100644 index 00000000000..33c910f6845 --- /dev/null +++ b/src/native-clr/CMakePresets.json.in @@ -0,0 +1,324 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + + "configurePresets": [ + { + "name": "common", + "hidden": true, + "generator": "Ninja", + "debug": { + "output": true + }, + "toolchainFile": "@AndroidNdkDirectory@/build/cmake/android.toolchain.cmake", + "cacheVariables": { + "ANDROID_NDK": "@AndroidNdkDirectory@", + "ANDROID_TOOLCHAIN": "clang", + "ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES": "ON", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_MAKE_PROGRAM": "@NinjaPath@", + "OUTPUT_PATH": "@OutputPath@", + "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", + "XA_BUILD_CONFIGURATION": "@XA_BUILD_CONFIGURATION@" + } + }, + + { + "name": "common-debug", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + + { + "name": "common-release", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + + { + "name": "default-common", + "hidden": true, + "inherits": "common", + "cacheVariables": { + "ANDROID_STL": "c++_static", + "ANDROID_CPP_FEATURES": "no-rtti exceptions" + } + }, + + { + "name": "analyzers-common", + "hidden": true, + "inherits": "common", + "cacheVariables": { + "ANDROID_STL": "c++_static", + "ANDROID_CPP_FEATURES": "rtti exceptions" + } + }, + + { + "name": "default-debug", + "hidden": true, + "inherits": ["default-common", "common-debug"] + }, + + { + "name": "default-release", + "hidden": true, + "inherits": ["default-common", "common-release"] + }, + + { + "name": "analyzers-debug", + "hidden": true, + "inherits": ["analyzers-common", "common-debug"] + }, + + { + "name": "analyzers-release", + "hidden": true, + "inherits": ["analyzers-common", "common-release"] + }, + + { + "name": "common-armeabi-v7a", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "armeabi-v7a", + "ANDROID_NATIVE_API_LEVEL": "@NDK_ARMEABI_V7_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_ARMEABI_V7_API_NET@", + "ANDROID_RID": "android-arm" + } + }, + + { + "name": "common-arm64-v8a", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "arm64-v8a", + "ANDROID_NATIVE_API_LEVEL": "@NDK_ARM64_V8A_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_ARM64_V8A_API_NET@", + "ANDROID_RID": "android-arm64" + } + }, + + { + "name": "common-x86", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "x86", + "ANDROID_NATIVE_API_LEVEL": "@NDK_X86_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_X86_API_NET@", + "ANDROID_RID": "android-x86" + } + }, + + { + "name": "common-x86_64", + "hidden": true, + "cacheVariables": { + "ANDROID_ABI": "x86_64", + "ANDROID_NATIVE_API_LEVEL": "@NDK_X86_64_API_NET@", + "ANDROID_PLATFORM": "android-@NDK_X86_64_API_NET@", + "ANDROID_RID": "android-x64" + } + }, + + { + "name": "asan-common", + "hidden": true, + "cacheVariables": { + "ENABLE_CLANG_ASAN": "ON" + } + }, + + { + "name": "ubsan-common", + "hidden": true, + "cacheVariables": { + "ENABLE_CLANG_UBSAN": "ON" + } + }, + + { + "name": "default-debug-armeabi-v7a", + "inherits": ["default-common", "common-debug", "common-armeabi-v7a"] + }, + + { + "name": "default-release-armeabi-v7a", + "inherits": ["default-common", "common-release", "common-armeabi-v7a"] + }, + + { + "name": "analyzers-debug-armeabi-v7a", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-armeabi-v7a"] + }, + + { + "name": "analyzers-release-armeabi-v7a", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-armeabi-v7a"] + }, + + { + "name": "asan-release-armeabi-v7a", + "inherits": ["analyzers-release-armeabi-v7a", "asan-common"] + }, + + { + "name": "asan-debug-armeabi-v7a", + "inherits": ["analyzers-debug-armeabi-v7a", "asan-common"] + }, + + { + "name": "ubsan-release-armeabi-v7a", + "inherits": ["analyzers-release-armeabi-v7a", "ubsan-common"] + }, + + { + "name": "ubsan-debug-armeabi-v7a", + "inherits": ["analyzers-debug-armeabi-v7a", "ubsan-common"] + }, + + + + { + "name": "default-debug-arm64-v8a", + "inherits": ["default-common", "common-debug", "common-arm64-v8a"] + }, + + { + "name": "default-release-arm64-v8a", + "inherits": ["default-common", "common-release", "common-arm64-v8a"] + }, + + { + "name": "analyzers-debug-arm64-v8a", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-arm64-v8a"] + }, + + { + "name": "analyzers-release-arm64-v8a", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-arm64-v8a"] + }, + + { + "name": "asan-release-arm64-v8a", + "inherits": ["analyzers-release-arm64-v8a", "asan-common"] + }, + + { + "name": "asan-debug-arm64-v8a", + "inherits": ["analyzers-debug-arm64-v8a", "asan-common"] + }, + + { + "name": "ubsan-release-arm64-v8a", + "inherits": ["analyzers-release-arm64-v8a", "ubsan-common"] + }, + + { + "name": "ubsan-debug-arm64-v8a", + "inherits": ["analyzers-debug-arm64-v8a", "ubsan-common"] + }, + + + + { + "name": "default-debug-x86", + "inherits": ["default-common", "common-debug", "common-x86"] + }, + + { + "name": "default-release-x86", + "inherits": ["default-common", "common-release", "common-x86"] + }, + + { + "name": "analyzers-debug-x86", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-x86"] + }, + + { + "name": "analyzers-release-x86", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-x86"] + }, + + { + "name": "asan-release-x86", + "inherits": ["analyzers-release-x86", "asan-common"] + }, + + { + "name": "asan-debug-x86", + "inherits": ["analyzers-debug-x86", "asan-common"] + }, + + { + "name": "ubsan-release-x86", + "inherits": ["analyzers-release-x86", "ubsan-common"] + }, + + { + "name": "ubsan-debug-x86", + "inherits": ["analyzers-debug-x86", "ubsan-common"] + }, + + + + { + "name": "default-debug-x86_64", + "inherits": ["default-common", "common-debug", "common-x86_64"] + }, + + { + "name": "default-release-x86_64", + "inherits": ["default-common", "common-release", "common-x86_64"] + }, + + { + "name": "analyzers-debug-x86_64", + "hidden": true, + "inherits": ["analyzers-common", "common-debug", "common-x86_64"] + }, + + { + "name": "analyzers-release-x86_64", + "hidden": true, + "inherits": ["analyzers-common", "common-release", "common-x86_64"] + }, + + { + "name": "asan-release-x86_64", + "inherits": ["analyzers-release-x86_64", "asan-common"] + }, + + { + "name": "asan-debug-x86_64", + "inherits": ["analyzers-debug-x86_64", "asan-common"] + }, + + { + "name": "ubsan-release-x86_64", + "inherits": ["analyzers-release-x86_64", "ubsan-common"] + }, + + { + "name": "ubsan-debug-x86_64", + "inherits": ["analyzers-debug-x86_64", "ubsan-common"] + } + ] +} diff --git a/src/native-clr/host/CMakeLists.txt b/src/native-clr/host/CMakeLists.txt new file mode 100644 index 00000000000..b60cbc3b3ec --- /dev/null +++ b/src/native-clr/host/CMakeLists.txt @@ -0,0 +1,155 @@ +# Needed modules + +include(CheckIncludeFile) +include(CheckCXXSymbolExists) + +set(BUILD_STATIC_LIBRARY OFF) + +if(DEBUG_BUILD) + # Convince NDK to really optimize our Debug builds. Without this, NDK's cmake toolchain definition + # will force a -O0 on us and our "debug" build is not really for debugging of our native code but + # rather for "debug" builds of user apps - it has extra code but it has to be as fast as possible. + set(XA_COMPILER_FLAGS_DEBUG "-fno-limit-debug-info -O2") + set(CMAKE_C_FLAGS_DEBUG ${XA_COMPILER_FLAGS_DEBUG}) + set(CMAKE_CXX_FLAGS_DEBUG ${XA_COMPILER_FLAGS_DEBUG}) +elseif(NOT ANALYZERS_ENABLED) + set(BUILD_STATIC_LIBRARY OFF) # Turn off for now, until we implement dynamic runtime linking at app build time +endif() + +# Library directories +set(XA_LIBRARY_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/lib/${ANDROID_RID}") +set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/libstubs/${ANDROID_RID}") + +# Header checks + +# Sources +string(TOLOWER ${CMAKE_BUILD_TYPE} XAMARIN_NET_ANDROID_SUFFIX) +set(XAMARIN_NET_ANDROID_LIB "net-android${CHECKED_BUILD_INFIX}.${XAMARIN_NET_ANDROID_SUFFIX}") +set(XAMARIN_NET_ANDROID_STATIC_LIB "${XAMARIN_NET_ANDROID_LIB}-static") + +set(XAMARIN_MONODROID_SOURCES + host.cc + host-jni.cc +) + +list(APPEND LOCAL_CLANG_CHECK_SOURCES + ${XAMARIN_MONODROID_SOURCES} +) + +add_clang_check_sources("${LOCAL_CLANG_CHECK_SOURCES}") + +# Build +add_library( + ${XAMARIN_NET_ANDROID_LIB} + SHARED ${XAMARIN_MONODROID_SOURCES} +) + +if(BUILD_STATIC_LIBRARY) + add_library( + ${XAMARIN_NET_ANDROID_STATIC_LIB} + STATIC + ${XAMARIN_MONODROID_SOURCES} + ) + set_static_library_suffix(${XAMARIN_NET_ANDROID_STATIC_LIB}) +endif() + +macro(lib_target_options TARGET_NAME) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + HAVE_CONFIG_H + HAVE_LZ4 + JI_DLL_EXPORT + JI_NO_VISIBILITY + ) + + if(DONT_INLINE) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + NO_INLINE + ) + endif() + + if(DEBUG_BUILD AND NOT DISABLE_DEBUG) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + DEBUG + ) + endif() + + if (ENABLE_TIMING) + target_compile_definitions( + ${TARGET_NAME} + PRIVATE + MONODROID_TIMING + ) + endif() + + target_compile_options( + ${TARGET_NAME} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} + ${XA_COMMON_CXX_ARGS} + ) + + target_include_directories( + ${TARGET_NAME} BEFORE + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/include + ${EXTERNAL_DIR} + ${ROBIN_MAP_DIR}/include + ) + + target_include_directories( + ${TARGET_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ${MONO_RUNTIME_INCLUDE_DIR} + ${NATIVE_TRACING_INCLUDE_DIRS} + ${LIBUNWIND_INCLUDE_DIRS} + ) + + target_link_directories( + ${TARGET_NAME} + PRIVATE + ${NET_RUNTIME_DIR}/native + ) + + target_link_options( + ${TARGET_NAME} + PRIVATE + ${XA_DEFAULT_SYMBOL_VISIBILITY} + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} + ) + + target_link_libraries( + ${TARGET_NAME} + ${LINK_LIBS} + xa::xamarin-app-clr + ${SHARED_LIB_NAME} + xa::runtime-base-clr + xa::java-interop-clr +# xa::pinvoke-override-precompiled + xa::lz4-clr + -llog + ) +endmacro () + +lib_target_options(${XAMARIN_NET_ANDROID_LIB}) +xa_add_compile_definitions(${XAMARIN_NET_ANDROID_LIB}) +xa_add_include_directories(${XAMARIN_NET_ANDROID_LIB}) + +target_link_options(${XAMARIN_NET_ANDROID_LIB} + PRIVATE + -Wl,--version-script,${CMAKE_SOURCE_DIR}/libnet-android.map.txt + -Wl,--no-undefined-version +) + +if(BUILD_STATIC_LIBRARY) + lib_target_options(${XAMARIN_NET_ANDROID_STATIC_LIB}) + xa_add_compile_definitions(${XAMARIN_NET_ANDROID_STATIC_LIB}) + xa_add_include_directories(${XAMARIN_NET_ANDROID_STATIC_LIB}) +endif() diff --git a/src/native-clr/host/host-jni.cc b/src/native-clr/host/host-jni.cc new file mode 100644 index 00000000000..3e9af6e868a --- /dev/null +++ b/src/native-clr/host/host-jni.cc @@ -0,0 +1,43 @@ +#include +#include + +using namespace xamarin::android; + +JNIEXPORT jint JNICALL +JNI_OnLoad (JavaVM *vm, void *reserved) +{ + return Host::Java_JNI_OnLoad (vm, reserved); +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_dumpTimingData ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass klass) +{ + // if (internal_timing == nullptr) { + // return; + // } + + // internal_timing->dump (); +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_register (JNIEnv *env, [[maybe_unused]] jclass klass, jstring managedType, jclass nativeClass, jstring methods) +{ +} + +JNIEXPORT void JNICALL +Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, + jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, + jobjectArray assembliesJava, jboolean isEmulator, + jboolean haveSplitApks) +{ +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_propagateUncaughtException (JNIEnv *env, [[maybe_unused]] jclass klass, jobject javaThread, jthrowable javaException) +{ +} + +JNIEXPORT void +JNICALL Java_mono_android_Runtime_notifyTimeZoneChanged ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass klass) +{ +} diff --git a/src/native-clr/host/host.cc b/src/native-clr/host/host.cc new file mode 100644 index 00000000000..735ae4dfa60 --- /dev/null +++ b/src/native-clr/host/host.cc @@ -0,0 +1,11 @@ +#include +#include +#include + +using namespace xamarin::android; + +auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint +{ + AndroidSystem::init_max_gref_count (); + return JNI_VERSION_1_6; +} diff --git a/src/native-clr/include/constants.hh b/src/native-clr/include/constants.hh new file mode 100644 index 00000000000..e850723ec00 --- /dev/null +++ b/src/native-clr/include/constants.hh @@ -0,0 +1,96 @@ +#pragma once + +#include + +#include + +#include "shared/cpp-util.hh" + +namespace xamarin::android { + class Constants + { +#if INTPTR_MAX == INT64_MAX + static inline constexpr std::string_view BITNESS { "64bit" }; +#else + static inline constexpr std::string_view BITNESS { "32bit" }; +#endif + + public: + static constexpr std::string_view MANGLED_ASSEMBLY_NAME_EXT { ".so" }; + + private: + static constexpr std::string_view RUNTIME_CONFIG_BLOB_BASE_NAME { "libarc.bin" }; + static constexpr size_t runtime_config_blob_name_size = calc_size (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); + static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); + + public: + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY.data () }; + 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" }; + + 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*" }; + +#if defined(__arm__) + static constexpr std::string_view android_abi { "armeabi_v7a" }; + static constexpr std::string_view android_lib_abi { "armeabi-v7a" }; + static constexpr std::string_view runtime_identifier { "android-arm" }; +#elif defined(__aarch64__) + static constexpr std::string_view android_abi { "arm64_v8a" }; + static constexpr std::string_view android_lib_abi { "arm64-v8a" }; + static constexpr std::string_view runtime_identifier { "android-arm64" }; +#elif defined(__x86_64__) + static constexpr std::string_view android_abi { "x86_64" }; + static constexpr std::string_view android_lib_abi { "x86_64" }; + static constexpr std::string_view runtime_identifier { "android-x64" }; +#elif defined(__i386__) + static constexpr std::string_view android_abi { "x86" }; + static constexpr std::string_view android_lib_abi { "x86" }; + static constexpr std::string_view runtime_identifier { "android-x86" }; +#endif + + static constexpr std::string_view split_config_prefix { "/split_config." }; + static constexpr std::string_view split_config_extension { ".apk" }; + + static constexpr size_t split_config_abi_apk_name_size = calc_size (split_config_prefix, android_abi, split_config_extension); + static constexpr auto split_config_abi_apk_name = concat_string_views (split_config_prefix, android_abi, split_config_extension); + + // + // Indexes must match these of trhe `appDirs` array in src/java-runtime/mono/android/MonoPackageManager.java + // + static constexpr size_t APP_DIRS_FILES_DIR_INDEX = 0uz; + static constexpr size_t APP_DIRS_CACHE_DIR_INDEX = 1uz; + static constexpr size_t APP_DIRS_DATA_DIR_INDEX = 2uz; + + static inline constexpr size_t PROPERTY_VALUE_BUFFER_LEN = PROP_VALUE_MAX + 1uz; + + // 64-bit unsigned or 64-bit signed with sign + static constexpr size_t MAX_INTEGER_DIGIT_COUNT_BASE10 = 21uz; + static constexpr size_t INTEGER_BASE10_BUFFER_SIZE = MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz; + }; +} diff --git a/src/native-clr/include/host/host-jni.hh b/src/native-clr/include/host/host-jni.hh new file mode 100644 index 00000000000..2104c2b1846 --- /dev/null +++ b/src/native-clr/include/host/host-jni.hh @@ -0,0 +1,48 @@ +#pragma once + +#include + +extern "C" { + /* + * Class: mono_android_Runtime + * Method: initInternal + * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;ILjava/lang/ClassLoader;[Ljava/lang/String;IZZ)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_initInternal(JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jint, jobject, jobjectArray, jboolean, jboolean); + + /* + * Class: mono_android_Runtime + * Method: dumpTimingData + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_dumpTimingData (JNIEnv *, jclass); + + /* + * Class: mono_android_Runtime + * Method: init + * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;ILjava/lang/ClassLoader;[Ljava/lang/String;IZZ)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_init (JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jint, jobject, jobjectArray, jboolean, jboolean); + + /* + * Class: mono_android_Runtime + * Method: notifyTimeZoneChanged + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_notifyTimeZoneChanged (JNIEnv *, jclass); + + /* + * Class: mono_android_Runtime + * Method: propagateUncaughtException + * Signature: (Ljava/lang/Thread;Ljava/lang/Throwable;)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_propagateUncaughtException (JNIEnv *, jclass, jobject, jthrowable); + + /* + * Class: mono_android_Runtime + * Method: register + * Signature: (Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V + */ + JNIEXPORT void JNICALL Java_mono_android_Runtime_register (JNIEnv *, jclass, jstring, jclass, jstring); + +} diff --git a/src/native-clr/include/host/host.hh b/src/native-clr/include/host/host.hh new file mode 100644 index 00000000000..03e4186ebae --- /dev/null +++ b/src/native-clr/include/host/host.hh @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include "../shared/log_types.hh" + +namespace xamarin::android { + class Host + { + public: + static auto Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint; + }; +} diff --git a/src/native-clr/include/runtime-base/android-system.hh b/src/native-clr/include/runtime-base/android-system.hh new file mode 100644 index 00000000000..ad9975f9fc6 --- /dev/null +++ b/src/native-clr/include/runtime-base/android-system.hh @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include "../constants.hh" +#include "../shared/log_types.hh" +#include "strings.hh" + +namespace xamarin::android { + class AndroidSystem + { + public: + static auto get_max_gref_count () noexcept -> long + { + return max_gref_count; + } + + static void init_max_gref_count () noexcept + { + max_gref_count = get_max_gref_count_from_system (); + } + + static void set_running_in_emulator (bool yesno) noexcept + { + running_in_emulator = yesno; + } + + static auto monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int; + + private: + static auto lookup_system_property (std::string_view const &name, size_t &value_len) noexcept -> const char*; + static auto monodroid__system_property_get (std::string_view const&, char *sp_value, size_t sp_value_len) noexcept -> int; + static auto get_max_gref_count_from_system () noexcept -> long; + + private: + static inline long max_gref_count = 0; + static inline bool running_in_emulator = false; + }; +} diff --git a/src/native-clr/include/runtime-base/strings.hh b/src/native-clr/include/runtime-base/strings.hh new file mode 100644 index 00000000000..c3326e91cc1 --- /dev/null +++ b/src/native-clr/include/runtime-base/strings.hh @@ -0,0 +1,920 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "../shared/helpers.hh" +#include "../constants.hh" + +namespace xamarin::android { + static constexpr size_t SENSIBLE_TYPE_NAME_LENGTH = 128uz; + static constexpr size_t SENSIBLE_PATH_MAX = 256uz; + +#if DEBUG + static constexpr bool BoundsCheck = true; +#else + static constexpr bool BoundsCheck = false; +#endif + + class string_segment + { + public: + [[gnu::always_inline]] + auto initialized () const noexcept -> bool + { + return !_fresh; + } + + [[gnu::always_inline]] + auto start () const noexcept -> const char* + { + return _start; + } + + [[gnu::always_inline]] + auto length () const noexcept -> size_t + { + return _length; + } + + [[gnu::always_inline]] + auto empty () const noexcept -> bool + { + return length () == 0; + } + + [[gnu::always_inline]] + auto equal (const char *s) const noexcept -> bool + { + if (s == nullptr) { + return false; + } + + return equal (s, strlen (s)); + } + + [[gnu::always_inline]] + auto equal (const char *s, size_t s_length) const noexcept -> bool + { + if (s == nullptr) { + return false; + } + + if (length () != s_length) { + return false; + } + + if (!can_access (s_length)) [[unlikely]] { + return false; + } + + if (length () == 0) { + return true; + } + + return memcmp (_start, s, length ()) == 0; + } + + template [[gnu::always_inline]] + auto equal (const char (&s)[Size]) noexcept -> bool + { + return equal (s, Size - 1); + } + + [[gnu::always_inline]] + auto equal (std::string_view const& s) noexcept -> bool + { + return equal (s.data (), s.length ()); + } + + [[gnu::always_inline]] + auto starts_with_c (const char *s) const noexcept -> bool + { + if (s == nullptr) { + return false; + } + + return starts_with (s, strlen (s)); + } + + [[gnu::always_inline]] + auto starts_with (const char *s, size_t s_length) const noexcept -> bool + { + if (s == nullptr || !can_access (s_length)) { + return false; + } + + if (length () < s_length) { + return false; + } + + return memcmp (start (), s, s_length) == 0; + } + + template [[gnu::always_inline]] + auto starts_with (const char (&s)[Size]) const noexcept -> bool + { + return starts_with (s, Size - 1); + } + + [[gnu::always_inline]] + auto starts_with (std::string_view const& s) const noexcept -> bool + { + return starts_with (s.data (), s.length ()); + } + + [[gnu::always_inline]] + auto has_at (const char ch, size_t index) const noexcept -> bool + { + if (!can_access (index)) { + return false; + } + + return start ()[index] == ch; + } + + [[gnu::always_inline]] + auto find (const char ch, size_t start_index) const noexcept -> ssize_t + { + if (!can_access (start_index)) { + return -1; + } + + while (start_index <= length ()) { + if (start ()[start_index] == ch) { + return static_cast(start_index); + } + start_index++; + } + + return -1; + } + + template [[gnu::always_inline]] + auto to_integer (T &val, size_t start_index = 0uz, int base = 10) const noexcept -> bool + { + static_assert (std::is_integral_v); + constexpr T min = std::numeric_limits::min (); + constexpr T max = std::numeric_limits::max (); + using integer = typename std::conditional, int64_t, uint64_t>::type; + + if (length () == 0uz) { + return false; + } + + if (!can_access (start_index)) { + log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); + return false; + } + + // FIXME: this is less than ideal... we shouldn't need another buffer here + size_t slen = length () - start_index; + char s[slen + 1]; + + memcpy (s, start () + start_index, slen); + s[slen] = '\0'; + + integer ret; + char *endp; + bool out_of_range; + errno = 0; + if constexpr (std::is_signed_v) { + ret = strtoll (s, &endp, base); + out_of_range = ret < min || ret > max; + } else { + ret = strtoull (s, &endp, base); + out_of_range = ret > max; + } + + if (out_of_range || errno == ERANGE) { + log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); + return false; + } + + if (endp == s) { + log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); + return false; + } + + if (*endp != '\0') { + log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); + return false; + } + + val = static_cast(ret); + return true; + } + + private: + [[gnu::always_inline]] + auto can_access (size_t index) const noexcept -> bool + { + if (!initialized () || start () == nullptr) [[unlikely]] { + return false; + } + + if (index > length ()) { + return false; + } + + return true; + } + + protected: + size_t _last_index = 0uz; + bool _fresh = true; + const char *_start = nullptr; + size_t _length = 0uz; + + template friend class string_base; + }; + + template + class local_storage + { + protected: + using LocalStoreArray = std::array; + + public: + static constexpr bool has_resize = HasResize; + + public: + explicit local_storage (size_t size) noexcept + { + static_assert (MaxStackSize > 0, "MaxStackSize must be more than 0"); + init_store (size < MaxStackSize ? MaxStackSize : size); + } + + virtual ~local_storage () + { + free_store (); + } + + auto get () noexcept -> T* + { + return allocated_store == nullptr ? local_store.data () : allocated_store; + } + + auto get () const noexcept -> const T* + { + return allocated_store == nullptr ? local_store.data () : allocated_store; + } + + auto size () const noexcept -> size_t + { + return store_size; + } + + protected: + [[gnu::always_inline]] + void init_store (size_t new_size) noexcept + { + if (new_size > MaxStackSize) { + allocated_store = new T[new_size]; + } else { + allocated_store = nullptr; + } + store_size = new_size; + } + + [[gnu::always_inline]] + void free_store () noexcept + { + if (allocated_store == nullptr) { + return; + } + + delete[] allocated_store; + } + + [[gnu::always_inline]] + auto get_local_store () noexcept -> LocalStoreArray& + { + return local_store; + } + + [[gnu::always_inline]] + auto get_allocated_store () noexcept -> T* + { + return allocated_store; + } + + private: + size_t store_size; + LocalStoreArray local_store; + T* allocated_store; + }; + + // This class is meant to provide a *very* thin veneer (by design) over space allocated for *local* buffers - that + // is one which are not meant to survive the exit of the function they are created in. The idea is that the caller + // knows the size of the buffer they need and they want to put the buffer on stack, if it doesn't exceed a certain + // value, or dynamically allocate memory if more is needed. Even though the class could be used on its own, it's + // really meant to be a base for more specialized buffers. There are not many safeguards, by design - the code is + // meant to be performant. This is the reason why the size is static throughout the life of the object, so that we + // can perform as few checks as possible. + + template using static_local_storage_base = local_storage; + + template + class static_local_storage final : public static_local_storage_base + { + using base = static_local_storage_base; + + public: + explicit static_local_storage (size_t initial_size) noexcept + : base (initial_size) + {} + }; + + template using dynamic_local_storage_base = local_storage; + + template + class dynamic_local_storage final : public dynamic_local_storage_base + { + using base = dynamic_local_storage_base; + + public: + explicit dynamic_local_storage (size_t initial_size = 0uz) noexcept + : base (initial_size) + {} + + // + // If `new_size` is smaller than the current size and the dynamic store is allocated, data WILL NOT be + // preserved. + // + // If `new_size` is bigger than the current size bigger than MaxStackSize, data will be copied to the new + // dynamically allocated store + // + // If `new_size` is smaller or equal to `MaxStackSize`, no changes are made unless dynamic store was allocated, + // in which case it will be freed + // + void resize (size_t new_size) noexcept + { + size_t old_size = base::size (); + + if (new_size == old_size) { + return; + } + + if (new_size <= MaxStackSize) { + new_size = MaxStackSize; + base::free_store (); + return; + } + + if (new_size < old_size) { + base::free_store (); + base::init_store (new_size); + return; + } + + T* old_allocated_store = base::get_allocated_store (); + base::init_store (new_size); + + T* new_allocated_store = base::get_allocated_store (); + if (old_allocated_store != nullptr) { + std::memcpy (new_allocated_store, old_allocated_store, old_size); + delete[] old_allocated_store; + return; + } + + std::memcpy (new_allocated_store, base::get_local_store ().data (), MaxStackSize); + } + }; + + template + class string_base + { + protected: + static constexpr TChar NUL = '\0'; + static constexpr TChar ZERO = '0'; + + public: + explicit string_base (size_t initial_size = 0uz) + : buffer (initial_size) + { + // Currently we care only about `char`, maybe in the future we'll add support for `wchar` (if needed) + static_assert (std::is_same_v, "TChar must be an 8-bit character type"); + + clear (); + } + + explicit string_base (const string_segment &token) + : string_base (token.initialized () ? token.length () : 0) + { + if (token.initialized ()) { + assign (token.start (), token.length ()); + } + } + + [[gnu::always_inline]] + auto length () const noexcept -> size_t + { + return idx; + } + + [[gnu::always_inline]] + auto empty () const noexcept -> bool + { + return length () == 0; + } + + [[gnu::always_inline]] + void set_length (size_t new_length) noexcept + { + if (new_length >= buffer.size ()) { + return; + } + + idx = new_length; + terminate (); + } + + [[gnu::always_inline]] + void clear () noexcept + { + set_length (0); + buffer.get ()[0] = NUL; + } + + [[gnu::always_inline]] + void terminate () noexcept + { + buffer.get ()[idx] = NUL; + } + + [[gnu::always_inline]] + auto replace (const TChar c1, const TChar c2) noexcept -> string_base& + { + if (empty ()) { + return *this; + } + + for (size_t i = 0uz; i < length (); i++) { + if (buffer.get ()[i] == c1) { + buffer.get ()[i] = c2; + } + } + + return *this; + } + + [[gnu::always_inline]] + auto append (const TChar* s, size_t length) noexcept -> string_base& + { + if (s == nullptr || length == 0uz) { + return *this; + } + + resize_for_extra (length); + if constexpr (BoundsCheck) { + ensure_have_extra (length); + } + + std::memcpy (buffer.get () + idx, s, length); + idx += length; + buffer.get ()[idx] = NUL; + + return *this; + } + + template + [[gnu::always_inline]] + auto append (string_base const& str) noexcept -> string_base& + { + return append (str.get (), str.length ()); + } + + [[gnu::always_inline]] + auto append (std::string_view const& sv) noexcept -> string_base& + { + return append (sv.data (), sv.length ()); + } + + template [[gnu::always_inline]] + auto append (const char (&s)[Size]) noexcept -> string_base& + { + return append (s, Size - 1); + } + + [[gnu::always_inline]] + auto append_c (const char *s) noexcept -> string_base& + { + if (s == nullptr) + return *this; + + return append (s, strlen (s)); + } + + [[gnu::always_inline]] + auto append (int16_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (buffer.get (), i); + return *this; + } + + [[gnu::always_inline]] + auto append (uint16_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (int32_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (uint32_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (int64_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (uint64_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto assign (const TChar* s, size_t length) noexcept -> string_base& + { + idx = 0; + return append (s, length); + } + + [[gnu::always_inline]] + auto assign_c (const TChar* s) noexcept -> string_base& + { + if (s == nullptr) { + return *this; + } + + return assign (s, strlen (s)); + } + + [[gnu::always_inline]] + auto assign (std::string_view const& sv) noexcept -> string_base& + { + return assign (sv.data (), sv.size ()); + } + + template [[gnu::always_inline]] + auto assign (const char (&s)[Size]) noexcept -> string_base& + { + return assign (s, Size - 1); + } + + template + [[gnu::always_inline]] + auto assign (string_base const& str) noexcept -> string_base& + { + return assign (str.get (), str.length ()); + } + + [[gnu::always_inline]] + auto assign (const TChar* s, size_t offset, size_t count) noexcept -> string_base& + { + if (s == nullptr) { + return *this; + } + + if constexpr (BoundsCheck) { + size_t slen = strlen (s); + if (offset + count > slen) { + Helpers::abort_application ("Attempt to assign data from a string exceeds the source string length"); + } + } + + return assign (s + offset, count); + } + + [[gnu::always_inline]] + auto next_token (size_t start_index, const TChar separator, string_segment& token) const noexcept -> bool + { + size_t index; + if (token._fresh) { + token._fresh = false; + token._last_index = start_index; + index = start_index; + } else { + index = token._last_index + 1; + } + + token._start = nullptr; + token._length = 0; + if (token._last_index + 1 >= buffer.size ()) { + return false; + } + + const TChar *start = buffer.get () + index; + const TChar *p = start; + while (*p != NUL) { + if (*p == separator) { + break; + } + p++; + index++; + } + + token._last_index = *p == NUL ? buffer.size () : index; + token._start = start; + token._length = static_cast(p - start); + + return true; + } + + [[gnu::always_inline]] + auto next_token (const char separator, string_segment& token) const noexcept -> bool + { + return next_token (0, separator, token); + } + + [[gnu::always_inline]] + auto index_of (const TChar ch) const noexcept -> ssize_t + { + const TChar *p = buffer.get (); + while (p != nullptr && *p != NUL) { + if (*p == ch) { + return static_cast(p - buffer.get ()); + } + p++; + } + + return -1; + } + + [[gnu::always_inline]] + auto starts_with (const TChar *s, size_t s_length) const noexcept -> bool + { + if (s == nullptr || s_length == 0 || s_length > buffer.size ()) { + return false; + } + + return memcmp (buffer.get (), s, s_length) == 0; + } + + [[gnu::always_inline]] + auto starts_with_c (const char* s) noexcept -> bool + { + if (s == nullptr) { + return false; + } + + return starts_with (s, strlen (s)); + } + + template [[gnu::always_inline]] + auto starts_with (const char (&s)[Size]) noexcept -> bool + { + return starts_with (s, Size - 1); + } + + [[gnu::always_inline]] + auto starts_with (std::string_view const& s) noexcept -> bool + { + return starts_with (s.data (), s.length ()); + } + + [[gnu::always_inline]] + void set_length_after_direct_write (size_t new_length) noexcept + { + set_length (new_length); + terminate (); + } + + [[gnu::always_inline]] + void set_at (size_t index, const TChar ch) noexcept + { + ensure_valid_index (index); + TChar *p = buffer + index; + if (*p == NUL) { + return; + } + + *p = ch; + } + + [[gnu::always_inline]] + auto get_at (size_t index) const noexcept -> const TChar + { + ensure_valid_index (index); + return *(buffer.get () + index); + } + + [[gnu::always_inline]] + auto get_at (size_t index) noexcept -> TChar& + { + ensure_valid_index (index); + return *(buffer.get () + index); + } + + [[gnu::always_inline]] + auto get () const noexcept -> const TChar* + { + return buffer.get (); + } + + [[gnu::always_inline]] + auto get () noexcept -> TChar* + { + return buffer.get (); + } + + [[gnu::always_inline]] + auto size () const noexcept -> size_t + { + return buffer.size (); + } + + [[gnu::always_inline]] + auto operator[] (size_t index) const noexcept -> char + { + return get_at (index); + } + + [[gnu::always_inline]] + auto operator[] (size_t index) noexcept -> char& + { + return get_at (index); + } + + protected: + template [[gnu::always_inline]] + void append_integer (Integer i) noexcept + { + static_assert (std::is_integral_v); + + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + if constexpr (BoundsCheck) { + ensure_have_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + } + + if (i == 0) { + constexpr char zero[] = "0"; + constexpr size_t zero_len = sizeof(zero) - 1uz; + + append (zero, zero_len); + return; + } + + TChar temp_buf[Constants::MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz]; + TChar *p = temp_buf + Constants::MAX_INTEGER_DIGIT_COUNT_BASE10; + *p = NUL; + TChar *end = p; + + uint32_t x; + if constexpr (sizeof(Integer) > 4uz) { + uint64_t y; + + if constexpr (std::is_signed_v) { + y = static_cast(i > 0 ? i : -i); + } else { + y = static_cast(i); + } + while (y > std::numeric_limits::max ()) { + *--p = (y % 10) + ZERO; + y /= 10; + } + x = static_cast(y); + } else { + if constexpr (std::is_signed_v) { + x = static_cast(i > 0 ? i : -i); + } else { + x = static_cast(i); + } + } + + while (x > 0) { + *--p = (x % 10) + ZERO; + x /= 10; + } + + if constexpr (std::is_signed_v) { + if (i < 0) + *--p = '-'; + } + + append (p, static_cast(end - p)); + } + + [[gnu::always_inline]] + void ensure_valid_index (size_t access_index) const noexcept + { + if (access_index < idx && access_index < buffer.size ()) [[likely]] { + return; + } + + char *message = nullptr; + int n = asprintf (&message, "Index %zu is out of range (0 - %zu)", access_index, idx); + Helpers::abort_application (n == -1 ? "Index out of range" : message); + } + + [[gnu::always_inline]] + void ensure_have_extra (size_t length) noexcept + { + size_t needed_space = Helpers::add_with_overflow_check (length, idx + 1); + if (needed_space > buffer.size ()) { + char *message = nullptr; + int n = asprintf ( + &message, + "Attempt to store too much data in a buffer (capacity: %zu; exceeded by: %zu)", + buffer.size (), + needed_space - buffer.size () + ); + Helpers::abort_application (n == -1 ? "Attempt to store too much data in a buffer" : message); + } + } + + [[gnu::always_inline]] + void resize_for_extra (size_t needed_space) noexcept + { + if constexpr (TStorage::has_resize) { + size_t required_space = Helpers::add_with_overflow_check (needed_space, idx + 1uz); + size_t current_size = buffer.size (); + if (required_space > current_size) { + size_t new_size = Helpers::add_with_overflow_check (current_size, (current_size / 2uz)); + new_size = Helpers::add_with_overflow_check (new_size, required_space); + buffer.resize (new_size); + } + } + } + + private: + size_t idx; + TStorage buffer; + }; + + template + class static_local_string : public string_base, TChar> + { + using base = string_base, TChar>; + + public: + explicit static_local_string (size_t initial_size = 0uz) noexcept + : base (initial_size) + {} + + explicit static_local_string (const string_segment &token) noexcept + : base (token) + {} + + template + explicit static_local_string (const char (&str)[N]) + : base (N) + { + append (str); + } + }; + + template + class dynamic_local_string : public string_base, TChar> + { + using base = string_base, TChar>; + + public: + explicit dynamic_local_string (size_t initial_size = 0uz) + : base (initial_size) + {} + + explicit dynamic_local_string (const string_segment &token) noexcept + : base (token) + {} + + template + explicit dynamic_local_string (const char (&str)[N]) + : base (N) + { + base::append (str); + } + + explicit dynamic_local_string (std::string_view const& str) + : base (str.length ()) + { + base::append (str); + } + }; +} diff --git a/src/native-clr/include/shared/cpp-util.hh b/src/native-clr/include/shared/cpp-util.hh new file mode 100644 index 00000000000..2121305dd94 --- /dev/null +++ b/src/native-clr/include/shared/cpp-util.hh @@ -0,0 +1,212 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "helpers.hh" + +namespace xamarin::android::detail { + [[gnu::always_inline, gnu::flatten]] + static inline const char* + _format_message (const char *format, ...) noexcept + { + va_list ap; + va_start (ap, format); + + char *message; + int ret = vasprintf (&message, format, ap); + + va_end (ap); + return ret == -1 ? "Out of memory" : message; + } +} + +template F> +[[gnu::always_inline, gnu::flatten]] +static inline void +abort_unless (bool condition, F&& get_message, std::source_location sloc = std::source_location::current ()) noexcept +{ + static_assert (std::is_same::type, const char*>::value, "get_message must return 'const char*'"); + + if (condition) [[likely]] { + return; + } + + xamarin::android::Helpers::abort_application (std::invoke (get_message), true /* log_location */, sloc); +} + +[[gnu::always_inline, gnu::flatten]] +static inline void +abort_unless (bool condition, const char *message, std::source_location sloc = std::source_location::current ()) noexcept +{ + if (condition) [[likely]] { + return; + } + xamarin::android::Helpers::abort_application (message, true /* log_location */, sloc); +} + +template +[[gnu::always_inline, gnu::flatten]] +static inline void +abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_location sloc = std::source_location::current ()) noexcept +{ + abort_unless ( + ptr != nullptr, + [&ptr_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", ptr_name); }, + sloc + ); +} + +[[gnu::always_inline, gnu::flatten]] +static inline void +abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_location sloc = std::source_location::current ()) noexcept +{ + abort_unless ( + arg > 0, + [&arg_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", arg_name); }, + sloc + ); +} + +// Helper to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any +// of the calls present. +[[gnu::always_inline]] +inline void pd_log_location (std::source_location sloc = std::source_location::current ()) noexcept +{ + log_info_nocheck (LOG_DEFAULT, "loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); +} + +namespace xamarin::android +{ + template + struct CDeleter final + { + using UnderlyingType = std::remove_cv_t; + + void operator() (T* p) + { + UnderlyingType *ptr; + + if constexpr (std::is_const_v) { + ptr = const_cast*> (p); + } else { + ptr = p; + } + + std::free (reinterpret_cast(ptr)); + } + }; + + template + using c_unique_ptr = std::unique_ptr>; + + template + using char_array = std::array; + + template + constexpr auto concat_const (const char (&...parts)[Length]) + { + // `parts` being constant string arrays, Length for each of them includes the trailing NUL byte, thus the + // `sizeof... (Length)` part which subtracts the number of template parameters - the amount of NUL bytes so that + // we don't waste space. + constexpr size_t total_length = (... + Length) - sizeof... (Length); + char_array ret; // lgtm [cpp/paddingbyteinformationdisclosure] the buffer is filled in the loop below + ret[total_length] = 0; + + size_t i = 0uz; + for (char const* from : {parts...}) { + for (; *from != '\0'; i++) { + ret[i] = *from++; + } + } + + return ret; + }; + + template + concept StringViewPart = std::is_same_v; + + template + consteval auto concat_string_views (T const&... parts) + { + std::array ret; // lgtm [cpp/paddingbyteinformationdisclosure] the buffer is filled in the loop below + ret[TotalLength] = 0; + + size_t i = 0; + for (std::string_view const& sv : {parts...}) { + for (const char ch : sv) { + ret[i] = ch; + i++; + } + } + + return ret; + } + + consteval size_t calc_size (std::string_view const& sv1) noexcept + { + return sv1.size (); + } + + template + consteval size_t calc_size (std::string_view const& sv1, T const&... other_svs) noexcept + { + return sv1.size () + calc_size (other_svs...); + } + + template , int> = 0> + constexpr TEnum operator & (TEnum l, TEnum r) noexcept + { + using etype = std::underlying_type_t; + return static_cast(static_cast(l) & static_cast(r)); + } + + template , int> = 0> + constexpr TEnum& operator &= (TEnum& l, TEnum r) noexcept + { + return l = (l & r); + } + + template , int> = 0> + constexpr TEnum operator | (TEnum l, TEnum r) noexcept + { + using etype = std::underlying_type_t; + return static_cast(static_cast(l) | static_cast(r)); + } + + template , int> = 0> + constexpr TEnum& operator |= (TEnum& l, TEnum r) noexcept + { + return l = (l | r); + } + + template , int> = 0> + constexpr TEnum operator ~ (TEnum r) noexcept + { + using etype = std::underlying_type_t; + return static_cast (~static_cast(r)); + } + + template , int> = 0> + constexpr TEnum operator ^ (TEnum l, TEnum r) noexcept + { + using etype = std::underlying_type_t; + return static_cast(static_cast(l) ^ static_cast(r)); + } + + template , int> = 0> + constexpr TEnum& operator ^= (TEnum& l, TEnum r) noexcept + { + return l = (l ^ r); + } +} diff --git a/src/native-clr/include/shared/helpers.hh b/src/native-clr/include/shared/helpers.hh new file mode 100644 index 00000000000..22e29b40f25 --- /dev/null +++ b/src/native-clr/include/shared/helpers.hh @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include +#include + +#include + +using namespace std::string_view_literals; + +namespace xamarin::android +{ + namespace detail { + template + concept TPointer = requires { std::is_pointer_v; }; + } + + class [[gnu::visibility("hidden")]] Helpers + { + public: + template + [[gnu::always_inline]] + static auto add_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret + { + constexpr bool DoNotLogLocation = false; + Ret ret; + + if (__builtin_add_overflow (a, b, &ret)) [[unlikely]] { + // It will leak memory, but it's fine, we're exiting the app anyway + char *message = nullptr; + int n = asprintf (&message, "Integer overflow on addition at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (n == -1 ? "Integer overflow on addition" : message, DoNotLogLocation, sloc); + } + + return ret; + } + + template + [[gnu::always_inline]] + static auto multiply_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret + { + constexpr bool DoNotLogLocation = false; + Ret ret; + + if (__builtin_mul_overflow (a, b, &ret)) [[unlikely]] { + // It will leak memory, but it's fine, we're exiting the app anyway + char *message = nullptr; + int n = asprintf (&message, "Integer overflow on multiplication at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (n == -1 ? "Integer overflow on multiplication" : message, DoNotLogLocation, sloc); + } + + return ret; + } + + [[noreturn]] + static void abort_application (LogCategories category, const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; + + [[noreturn]] + static void abort_application (LogCategories category, std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (category, message.c_str (), log_location, sloc); + } + + [[noreturn]] + static void abort_application (LogCategories category, std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (category, message.data (), log_location, sloc); + } + + [[noreturn]] + static void abort_application (const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (LOG_DEFAULT, message, log_location, sloc); + } + + [[noreturn]] + static void abort_application (std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (LOG_DEFAULT, message.c_str (), log_location, sloc); + } + + [[noreturn]] + static void abort_application (std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (LOG_DEFAULT, message.data (), log_location, sloc); + } + }; + + template [[gnu::always_inline]] + static inline constexpr auto pointer_add (TPtr ptr, size_t offset) noexcept -> TRet + { + return reinterpret_cast(reinterpret_cast(ptr) + offset); + } + + [[gnu::always_inline]] + static inline constexpr auto optional_string (const char* s, const char *replacement = nullptr) noexcept -> const char* + { + if (s != nullptr) [[likely]] { + return s; + } + + return replacement == nullptr ? "" : replacement; + } +} diff --git a/src/native-clr/include/shared/log_level.hh b/src/native-clr/include/shared/log_level.hh new file mode 100644 index 00000000000..fc7a7566910 --- /dev/null +++ b/src/native-clr/include/shared/log_level.hh @@ -0,0 +1,26 @@ +#pragma once + +#include + +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 + }; +} diff --git a/src/native-clr/include/shared/log_types.hh b/src/native-clr/include/shared/log_types.hh new file mode 100644 index 00000000000..66b1cae5097 --- /dev/null +++ b/src/native-clr/include/shared/log_types.hh @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include + +#include "java-interop-logger.h" +#include "log_level.hh" + +// We redeclare macros here +#if defined(log_debug) +#undef log_debug +#endif + +#if defined(log_info) +#undef log_info +#endif + +#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ + do { \ + if ((log_categories & ((_category_))) != 0) { \ + ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ + } \ + } while (0) + +// +// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec +// + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +namespace xamarin::android { + // 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; +} + +template [[gnu::always_inline]] +static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) +{ + log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Debug, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) +{ + log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Info, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); +} + +extern unsigned int log_categories; diff --git a/src/native-clr/include/shared/xxhash.hh b/src/native-clr/include/shared/xxhash.hh new file mode 100644 index 00000000000..b66c2ce309a --- /dev/null +++ b/src/native-clr/include/shared/xxhash.hh @@ -0,0 +1,192 @@ +#pragma once + +#if INTPTR_MAX == INT64_MAX +#define XXH_NO_STREAM +#define XXH_INLINE_ALL +#define XXH_NAMESPACE xaInternal_ +#include +#include +#endif + +// +// Based on original code at https://github.com/ekpyron/xxhashct +// +// Original code license: +// + +/** +* MIT License +* +* Copyright (c) 2021 Zachary Arnaise +* +* 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 +#include + +namespace xamarin::android +{ + class xxhash32 final + { + static constexpr uint32_t PRIME1 = 0x9E3779B1U; + static constexpr uint32_t PRIME2 = 0x85EBCA77U; + static constexpr uint32_t PRIME3 = 0xC2B2AE3DU; + static constexpr uint32_t PRIME4 = 0x27D4EB2FU; + static constexpr uint32_t PRIME5 = 0x165667B1U; + + public: + // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily + // understood and to run compile-time algorithm correctness tests + template + [[gnu::always_inline]] + static constexpr auto hash (const char *input, size_t len) noexcept -> uint32_t + { + return finalize ( + (len >= 16 ? h16bytes (input, len) : Seed + PRIME5) + static_cast(len), + (input) + (len & ~0xFU), + len & 0xF + ); + } + + template + [[gnu::always_inline]] + static constexpr auto hash (const char (&input)[Size]) noexcept -> uint32_t + { + return hash (input, Size - 1); + } + + template + [[gnu::always_inline]] + static constexpr auto hash (std::string_view const& input) noexcept -> uint32_t + { + return hash (input.data (), input.length ()); + } + + private: + // 32-bit rotate left. + template [[gnu::always_inline]] + static constexpr auto rotl (uint32_t x) noexcept -> uint32_t + { + return ((x << Bits) | (x >> (32 - Bits))); + } + + // Normal stripe processing routine. + [[gnu::always_inline]] + static constexpr auto round (uint32_t acc, const uint32_t input) noexcept -> uint32_t + { + return rotl<13> (acc + (input * PRIME2)) * PRIME1; + } + + template [[gnu::always_inline]] + static constexpr auto avalanche_step (const uint32_t h) noexcept -> uint32_t + { + return (h ^ (h >> RShift)) * Prime; + } + + // Mixes all bits to finalize the hash. + [[gnu::always_inline]] + static constexpr auto avalanche (const uint32_t h) noexcept -> uint32_t + { + return + avalanche_step<16, 1> ( + avalanche_step<13, PRIME3> ( + avalanche_step <15, PRIME2> (h) + ) + ); + } + + // little-endian version: all our target platforms are little-endian + [[gnu::always_inline]] + static constexpr auto endian32 (const char *v) noexcept -> uint32_t + { + return + static_cast(static_cast(v[0])) | + (static_cast(static_cast(v[1])) << 8) | + (static_cast(static_cast(v[2])) << 16) | + (static_cast(static_cast(v[3])) << 24); + } + + [[gnu::always_inline]] + static constexpr auto fetch32 (const char *p, const uint32_t v) noexcept -> uint32_t + { + return round (v, endian32 (p)); + } + + // Processes the last 0-15 bytes of p. + [[gnu::always_inline]] + static constexpr auto finalize (const uint32_t h, const char *p, size_t len) noexcept -> uint32_t + { + return + (len >= 4) ? finalize (rotl<17> (h + (endian32 (p) * PRIME3)) * PRIME4, p + 4, len - 4) : + (len > 0) ? finalize (rotl<11> (h + (static_cast(*p) * PRIME5)) * PRIME1, p + 1, len - 1) : + avalanche (h); + } + + [[gnu::always_inline]] + static constexpr auto h16bytes (const char *p, size_t len, const uint32_t v1, const uint32_t v2, const uint32_t v3, const uint32_t v4) noexcept -> uint32_t + { + return + (len >= 16) ? h16bytes (p + 16, len - 16, fetch32 (p, v1), fetch32 (p+4, v2), fetch32 (p+8, v3), fetch32 (p+12, v4)) : + rotl<1> (v1) + rotl<7> (v2) + rotl<12> (v3) + rotl<18> (v4); + } + + // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily + // understood + template + [[gnu::always_inline]] + static constexpr auto h16bytes (const char *p, size_t len) noexcept -> uint32_t + { + return h16bytes(p, len, Seed + PRIME1 + PRIME2, Seed + PRIME2, Seed, Seed - PRIME1); + } + }; + +#if INTPTR_MAX == INT64_MAX + class xxhash64 final + { + public: + [[gnu::always_inline]] + static auto hash (const char *p, size_t len) noexcept -> XXH64_hash_t + { + return XXH3_64bits (static_cast(p), len); + } + + [[gnu::always_inline]] + static consteval auto hash (std::string_view const& input) noexcept -> XXH64_hash_t + { + return constexpr_xxh3::XXH3_64bits_const (input.data (), input.length ()); + } + + // The C XXH64_64bits function from xxhash.h is not `constexpr` or `consteval`, so we cannot call it here. + // At the same time, at build time performance is not that important, so we call the "unoptmized" `consteval` + // C++ implementation here + template [[gnu::always_inline]] + static consteval auto hash (const char (&input)[Size]) noexcept -> XXH64_hash_t + { + return constexpr_xxh3::XXH3_64bits_const (input); + } + }; + + using hash_t = XXH64_hash_t; + using xxhash = xxhash64; +#else + using hash_t = uint32_t; + using xxhash = xxhash32; +#endif +} diff --git a/src/native-clr/include/startup/zip.hh b/src/native-clr/include/startup/zip.hh new file mode 100644 index 00000000000..96afac707bd --- /dev/null +++ b/src/native-clr/include/startup/zip.hh @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include + +#include +#include + +namespace xamarin::android { + class Zip + { + private: + static inline constexpr off_t ZIP_EOCD_LEN = 22; + static inline constexpr off_t ZIP_CENTRAL_LEN = 46; + static inline constexpr off_t ZIP_LOCAL_LEN = 30; + + static inline constexpr std::string_view ZIP_CENTRAL_MAGIC { "PK\1\2" }; + static inline constexpr std::string_view ZIP_LOCAL_MAGIC { "PK\3\4" }; + static inline constexpr std::string_view ZIP_EOCD_MAGIC { "PK\5\6" }; + + static constexpr std::string_view zip_path_separator { "/" }; + static constexpr std::string_view apk_lib_dir_name { "lib" }; + + static constexpr size_t assemblies_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); + static constexpr auto assemblies_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); + + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; + }; +} diff --git a/src/native-clr/include/xamarin-app.hh b/src/native-clr/include/xamarin-app.hh new file mode 100644 index 00000000000..bcf6287c233 --- /dev/null +++ b/src/native-clr/include/xamarin-app.hh @@ -0,0 +1,380 @@ +// Dear Emacs, this is a -*- C++ -*- header +#pragma once + +#include + +#include + +#include "shared/xxhash.hh" + +static constexpr uint64_t FORMAT_TAG = 0x00035E6972616D58; // 'Xmari^XY' where XY is the format version +static constexpr uint32_t COMPRESSED_DATA_MAGIC = 0x5A4C4158; // 'XALZ', little-endian +static constexpr uint32_t ASSEMBLY_STORE_MAGIC = 0x41424158; // 'XABA', little-endian + +// The highest bit of assembly store version is a 64-bit ABI flag +#if INTPTR_MAX == INT64_MAX +static constexpr uint32_t ASSEMBLY_STORE_64BIT_FLAG = 0x80000000; +#else +static constexpr uint32_t ASSEMBLY_STORE_64BIT_FLAG = 0x00000000; +#endif + +// The second-to-last byte denotes the actual ABI +#if defined(__aarch64__) +static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00010000; +#elif defined(__arm__) +static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00020000; +#elif defined(__x86_64__) +static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00030000; +#elif defined(__i386__) +static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00040000; +#endif + +// Increase whenever an incompatible change is made to the assembly store format +static constexpr uint32_t ASSEMBLY_STORE_FORMAT_VERSION = 2 | ASSEMBLY_STORE_64BIT_FLAG | ASSEMBLY_STORE_ABI; + +static constexpr uint32_t MODULE_MAGIC_NAMES = 0x53544158; // 'XATS', little-endian +static constexpr uint32_t MODULE_INDEX_MAGIC = 0x49544158; // 'XATI', little-endian +static constexpr uint8_t MODULE_FORMAT_VERSION = 2; // Keep in sync with the value in src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs + +#if defined (DEBUG) +struct BinaryTypeMapHeader +{ + uint32_t magic; + uint32_t version; + uint32_t entry_count; + uint32_t java_name_width; + uint32_t managed_name_width; + uint32_t assembly_name_length; +}; + +struct TypeMapIndexHeader +{ + uint32_t magic; + uint32_t version; + uint32_t entry_count; + uint32_t module_file_name_width; +}; + +struct TypeMapEntry +{ + const char *from; + const char *to; +}; + +// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs +struct TypeMap +{ + uint32_t entry_count; + char *assembly_name; + uint8_t *data; + const TypeMapEntry *java_to_managed; + const TypeMapEntry *managed_to_java; +}; +#else +struct TypeMapModuleEntry +{ + uint32_t type_token_id; + uint32_t java_map_index; +}; + +struct TypeMapModule +{ + uint8_t module_uuid[16]; + uint32_t entry_count; + uint32_t duplicate_count; + TypeMapModuleEntry const *map; + TypeMapModuleEntry const *duplicate_map; + char const *assembly_name; + uint8_t *image; + uint32_t java_name_width; + uint8_t *java_map; +}; + +struct TypeMapJava +{ + uint32_t module_index; + uint32_t type_token_id; + uint32_t java_name_index; +}; +#endif + +struct CompressedAssemblyHeader +{ + uint32_t magic; // COMPRESSED_DATA_MAGIC + uint32_t descriptor_index; + uint32_t uncompressed_length; +}; + +struct CompressedAssemblyDescriptor +{ + uint32_t uncompressed_file_size; + bool loaded; + uint8_t *data; +}; + +struct CompressedAssemblies +{ + uint32_t count; + CompressedAssemblyDescriptor *descriptors; +}; + +struct XamarinAndroidBundledAssembly +{ + int32_t file_fd; + char *file_name; + uint32_t data_offset; + uint32_t data_size; + uint8_t *data; + uint32_t name_length; + char *name; +}; + +// +// Assembly store format +// +// Each target ABI/architecture has a single assembly store file, composed of the following parts: +// +// [HEADER] +// [INDEX] +// [ASSEMBLY_DESCRIPTORS] +// [ASSEMBLY DATA] +// +// Formats of the sections above are as follows: +// +// HEADER (fixed size) +// [MAGIC] uint; value: 0x41424158 +// [FORMAT_VERSION] uint; store format version number +// [ENTRY_COUNT] uint; number of entries in the store +// [INDEX_ENTRY_COUNT] uint; number of entries in the index +// [INDEX_SIZE] uint; index size in bytes +// +// INDEX (variable size, HEADER.ENTRY_COUNT*2 entries, for assembly names with and without the extension) +// [NAME_HASH] uint on 32-bit platforms, ulong on 64-bit platforms; xxhash of the assembly name +// [DESCRIPTOR_INDEX] uint; index into in-store assembly descriptor array +// +// ASSEMBLY_DESCRIPTORS (variable size, HEADER.ENTRY_COUNT entries), each entry formatted as follows: +// [MAPPING_INDEX] uint; index into a runtime array where assembly data pointers are stored +// [DATA_OFFSET] uint; offset from the beginning of the store to the start of assembly data +// [DATA_SIZE] uint; size of the stored assembly data +// [DEBUG_DATA_OFFSET] uint; offset from the beginning of the store to the start of assembly PDB data, 0 if absent +// [DEBUG_DATA_SIZE] uint; size of the stored assembly PDB data, 0 if absent +// [CONFIG_DATA_OFFSET] uint; offset from the beginning of the store to the start of assembly .config contents, 0 if absent +// [CONFIG_DATA_SIZE] uint; size of the stored assembly .config contents, 0 if absent +// +// ASSEMBLY_NAMES (variable size, HEADER.ENTRY_COUNT entries), each entry formatted as follows: +// [NAME_LENGTH] uint: length of assembly name +// [NAME] byte: UTF-8 bytes of assembly name, without the NUL terminator +// + +// +// The structures which are found in the store files must be packed to avoid problems when calculating offsets (runtime +// size of a structure can be different than the real data size) +// +struct [[gnu::packed]] AssemblyStoreHeader final +{ + uint32_t magic; + uint32_t version; + uint32_t entry_count; + uint32_t index_entry_count; + uint32_t index_size; // index size in bytes +}; + +struct [[gnu::packed]] AssemblyStoreIndexEntry final +{ + xamarin::android::hash_t name_hash; + uint32_t descriptor_index; +}; + +struct [[gnu::packed]] AssemblyStoreEntryDescriptor final +{ + uint32_t mapping_index; + + uint32_t data_offset; + uint32_t data_size; + + uint32_t debug_data_offset; + uint32_t debug_data_size; + + uint32_t config_data_offset; + uint32_t config_data_size; +}; + +struct AssemblyStoreRuntimeData final +{ + uint8_t *data_start; + uint32_t assembly_count; + uint32_t index_entry_count; + AssemblyStoreEntryDescriptor *assemblies; +}; + +struct AssemblyStoreSingleAssemblyRuntimeData final +{ + uint8_t *image_data; + uint8_t *debug_info_data; + uint8_t *config_data; + AssemblyStoreEntryDescriptor *descriptor; +}; + +// Keep in strict sync with: +// src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs +// src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs +struct ApplicationConfig +{ + bool uses_assembly_preload; + bool jni_add_native_method_registration_attribute_present; + bool have_runtime_config_blob; + bool marshal_methods_enabled; + bool ignore_split_configs; + uint32_t package_naming_policy; + uint32_t environment_variable_count; + uint32_t system_property_count; + uint32_t number_of_assemblies_in_apk; + uint32_t bundled_assembly_name_width; + uint32_t number_of_dso_cache_entries; + uint32_t number_of_aot_cache_entries; + uint32_t number_of_shared_libraries; + uint32_t android_runtime_jnienv_class_token; + uint32_t jnienv_initialize_method_token; + uint32_t jnienv_registerjninatives_method_token; + uint32_t jni_remapping_replacement_type_count; + uint32_t jni_remapping_replacement_method_index_entry_count; + const char *android_package_name; +}; + +struct DSOApkEntry +{ + uint64_t name_hash; + uint32_t offset; // offset into the APK + int32_t fd; // apk file descriptor +}; + +struct DSOCacheEntry +{ + uint64_t hash; + uint64_t real_name_hash; + bool ignore; + const char *name; + void *handle; +}; + +struct JniRemappingString +{ + const uint32_t length; + const char *str; +}; + +struct JniRemappingReplacementMethod +{ + const char *target_type; + const char *target_name; + // const char *target_signature; + // const int32_t param_count; + const bool is_static; +}; + +struct JniRemappingIndexMethodEntry +{ + const JniRemappingString name; + const JniRemappingString signature; + const JniRemappingReplacementMethod replacement; +}; + +struct JniRemappingIndexTypeEntry +{ + const JniRemappingString name; + const uint32_t method_count; + const JniRemappingIndexMethodEntry *methods; +}; + +struct JniRemappingTypeReplacementEntry +{ + const JniRemappingString name; + const char *replacement; +}; + +extern "C" { + [[gnu::visibility("default")]] extern const JniRemappingIndexTypeEntry jni_remapping_method_replacement_index[]; + [[gnu::visibility("default")]] extern const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[]; + + [[gnu::visibility("default")]] extern const uint64_t format_tag; + +#if defined (DEBUG) + [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs +#else + [[gnu::visibility("default")]] extern const uint32_t map_module_count; + [[gnu::visibility("default")]] extern const uint32_t java_type_count; + [[gnu::visibility("default")]] extern const char* const java_type_names[]; + [[gnu::visibility("default")]] extern TypeMapModule map_modules[]; + [[gnu::visibility("default")]] extern const TypeMapJava map_java[]; + [[gnu::visibility("default")]] extern const xamarin::android::hash_t map_java_hashes[]; +#endif + + [[gnu::visibility("default")]] extern CompressedAssemblies compressed_assemblies; + [[gnu::visibility("default")]] extern const ApplicationConfig application_config; + [[gnu::visibility("default")]] extern const char* const app_environment_variables[]; + [[gnu::visibility("default")]] extern const char* const app_system_properties[]; + + [[gnu::visibility("default")]] extern const char* const mono_aot_mode_name; + + [[gnu::visibility("default")]] extern XamarinAndroidBundledAssembly bundled_assemblies[]; + [[gnu::visibility("default")]] extern AssemblyStoreSingleAssemblyRuntimeData assembly_store_bundled_assemblies[]; + [[gnu::visibility("default")]] extern AssemblyStoreRuntimeData assembly_store; + + [[gnu::visibility("default")]] extern DSOCacheEntry dso_cache[]; + [[gnu::visibility("default")]] extern DSOCacheEntry aot_dso_cache[]; + [[gnu::visibility("default")]] extern DSOApkEntry dso_apk_entries[]; +} + +// +// Support for marshal methods +// +#if defined (RELEASE) +struct MarshalMethodsManagedClass +{ + const uint32_t token; + void *klass; +}; + +// Number of assembly name forms for which we generate hashes (essentially file name mutations. For instance +// `HelloWorld.dll`, `HelloWorld`, `en-US/HelloWorld` etc). This is multiplied by the number of assemblies in the apk to +// obtain number of entries in the `assembly_image_cache_hashes` and `assembly_image_cache_indices` entries +constexpr uint32_t number_of_assembly_name_forms_in_image_cache = 3; + +// These 3 arrays constitute the cache used to store pointers to loaded managed assemblies. +// Three arrays are used so that we can have multiple hashes pointing to the same MonoImage*. +// +// This is done by the `assembly_image_cache_hashes` containing hashes for all mutations of some +// assembly's name (e.g. with culture prefix, without extension etc) and position of that hash in +// `assembly_image_cache_hashes` is an index into `assembly_image_cache_indices` which, in turn, +// stores final index into the `assembly_image_cache` array. +// +[[gnu::visibility("default")]] extern void* assembly_image_cache[]; +[[gnu::visibility("default")]] extern const uint32_t assembly_image_cache_indices[]; +[[gnu::visibility("default")]] extern const xamarin::android::hash_t assembly_image_cache_hashes[]; + +// Number of unique classes which contain native callbacks we bind +[[gnu::visibility("default")]] extern uint32_t marshal_methods_number_of_classes; +[[gnu::visibility("default")]] extern MarshalMethodsManagedClass marshal_methods_class_cache[]; + +// +// These tables store names of classes and managed callback methods used in the generated marshal methods +// code. They are used just for error reporting. +// +// Class names are found at the same indexes as their corresponding entries in the `marshal_methods_class_cache` array +// above. Method names are stored as token:name pairs and the array must end with an "invalid" terminator entry (token +// == 0; name == nullptr) +// +struct MarshalMethodName +{ + // combination of assembly index (high 32 bits) and method token (low 32 bits) + const uint64_t id; + const char *name; +}; + +[[gnu::visibility("default")]] extern const char* const mm_class_names[]; +[[gnu::visibility("default")]] extern const MarshalMethodName mm_method_names[]; + +using get_function_pointer_fn = void(*)(uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr); + +[[gnu::visibility("default")]] extern void xamarin_app_init (JNIEnv *env, get_function_pointer_fn fn) noexcept; +#endif // def RELEASE diff --git a/src/native-clr/java-interop/CMakeLists.txt b/src/native-clr/java-interop/CMakeLists.txt new file mode 100644 index 00000000000..702401df40c --- /dev/null +++ b/src/native-clr/java-interop/CMakeLists.txt @@ -0,0 +1,50 @@ +set(LIB_NAME xa-java-interop-clr) +set(LIB_ALIAS xa::java-interop-clr) + +set(JAVA_INTEROP_SOURCES + ${JAVA_INTEROP_SRC_PATH}/java-interop-dlfcn.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop-mono.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc + ${JAVA_INTEROP_SRC_PATH}/java-interop.cc +) +add_clang_check_sources("${JAVA_INTEROP_SOURCES}") + +add_library( + ${LIB_NAME} + STATIC + ${JAVA_INTEROP_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +set_static_library_suffix(${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} +) + +if(DEBUG_BUILD) + set_target_properties( + ${LIB_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) +endif() + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native-clr/libnet-android.map.txt b/src/native-clr/libnet-android.map.txt new file mode 100644 index 00000000000..f7e3c7c9fdf --- /dev/null +++ b/src/native-clr/libnet-android.map.txt @@ -0,0 +1,12 @@ +LIBNET_ANDROID { + global: + JNI_OnLoad; + Java_mono_android_Runtime_dumpTimingData; + Java_mono_android_Runtime_init; + Java_mono_android_Runtime_notifyTimeZoneChanged; + Java_mono_android_Runtime_propagateUncaughtException; + Java_mono_android_Runtime_register; + + local: + *; +}; diff --git a/src/native-clr/lz4/CMakeLists.txt b/src/native-clr/lz4/CMakeLists.txt new file mode 100644 index 00000000000..16a35099fd5 --- /dev/null +++ b/src/native-clr/lz4/CMakeLists.txt @@ -0,0 +1,41 @@ +set(LIB_NAME xa-lz4-clr) +set(LIB_ALIAS xa::lz4-clr) + +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 + "$" +) + +if(DEBUG_BUILD) + set_target_properties( + ${LIB_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) +endif() + +xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native-clr/native-clr.csproj b/src/native-clr/native-clr.csproj new file mode 100644 index 00000000000..43244cd9e8c --- /dev/null +++ b/src/native-clr/native-clr.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0 + Debug + AnyCPU + Exe + false + + + + + + $(MicrosoftAndroidSdkOutDir)lib\ + + + + + + + + diff --git a/src/native-clr/native-clr.targets b/src/native-clr/native-clr.targets new file mode 100644 index 00000000000..dba9f075f5b --- /dev/null +++ b/src/native-clr/native-clr.targets @@ -0,0 +1,144 @@ + + + + + + + + + + + + + <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="java-interop\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="lz4\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Debug\CMakeCache.txt')" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Release\CMakeCache.txt')" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-clr-Debug" /> + <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-clr-Release" /> + + + + + + <_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)-clr-Debug + + + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> + $(CmakePath) + --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-clr-Release + + + + + + + + + + + + <_MonoDroidSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> + <_MonoDroidSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> + + + + + + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Debug\CMakeCache.txt')" /> + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Release\CMakeCache.txt')" /> + <_BuildAndroidRuntimesInputs Include="@(_MonoDroidSources)" /> + <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.debug.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.release.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app-clr.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app-clr.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-clr/runtime-base/CMakeLists.txt b/src/native-clr/runtime-base/CMakeLists.txt new file mode 100644 index 00000000000..7e42498b5e4 --- /dev/null +++ b/src/native-clr/runtime-base/CMakeLists.txt @@ -0,0 +1,55 @@ +set(LIB_NAME runtime-base-clr) +set(LIB_ALIAS xa::runtime-base-clr) + +set(XA_RUNTIME_BASE_SOURCES + android-system.cc +) +add_clang_check_sources("${XA_RUNTIME_BASE_SOURCES}") + +list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS + -ffunction-sections + -fdata-sections +) + +xa_check_c_args(RUNTIME_BASE_CXX_ARGS "${POTENTIAL_LOCAL_COMPILER_ARGS}") + +add_library( + ${LIB_NAME} + STATIC + ${XA_RUNTIME_BASE_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +set_static_library_suffix(${LIB_NAME}) + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} + ${RUNTIME_BASE_CXX_ARGS} +) + +target_include_directories( + ${LIB_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} +) + +target_link_libraries( + ${LIB_NAME} + PRIVATE + xa::shared-clr + xa::xamarin-app-clr +) + +if(DEBUG_BUILD) + set_target_properties( + ${LIB_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) +endif() + +xa_add_compile_definitions(${LIB_NAME}) +xa_add_include_directories(${LIB_NAME}) diff --git a/src/native-clr/runtime-base/android-system.cc b/src/native-clr/runtime-base/android-system.cc new file mode 100644 index 00000000000..fcf6a82b640 --- /dev/null +++ b/src/native-clr/runtime-base/android-system.cc @@ -0,0 +1,134 @@ +#include + +#include +#include +#include +#include + +using namespace xamarin::android; + +auto +AndroidSystem::lookup_system_property (std::string_view const& name, size_t &value_len) noexcept -> const char* +{ + value_len = 0; +#if defined (DEBUG) + BundledProperty *p = lookup_system_property (name); + if (p != nullptr) { + value_len = p->value_len; + return p->name; + } +#endif // DEBUG || !ANDROID + + if (application_config.system_property_count == 0) { + return nullptr; + } + + if (application_config.system_property_count % 2 != 0) { + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count); + return nullptr; + } + + const char *prop_name; + const char *prop_value; + for (size_t i = 0uz; i < application_config.system_property_count; i += 2uz) { + prop_name = app_system_properties[i]; + if (prop_name == nullptr || *prop_name == '\0') { + continue; + } + + if (strcmp (prop_name, name.data ()) == 0) { + prop_value = app_system_properties [i + 1uz]; + if (prop_value == nullptr || *prop_value == '\0') { + value_len = 0uz; + return ""; + } + + value_len = strlen (prop_value); + return prop_value; + } + } + + return nullptr; +} + +auto +AndroidSystem::monodroid__system_property_get (std::string_view const& name, char *sp_value, size_t sp_value_len) noexcept -> int +{ + if (name.empty () || sp_value == nullptr) { + return -1; + } + + char *buf = nullptr; + if (sp_value_len < Constants::PROPERTY_VALUE_BUFFER_LEN) { + size_t alloc_size = Helpers::add_with_overflow_check (Constants::PROPERTY_VALUE_BUFFER_LEN, 1uz); + log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); + buf = new char [alloc_size]; + } + + int len = __system_property_get (name.data (), buf ? buf : sp_value); + if (buf != nullptr) { + strncpy (sp_value, buf, sp_value_len); + sp_value [sp_value_len] = '\0'; + delete[] buf; + } + + return len; +} + +auto AndroidSystem::monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int +{ + int len = monodroid__system_property_get (name, value.get (), value.size ()); + if (len > 0) { + // Clumsy, but if we want direct writes to be fast, this is the price we pay + value.set_length_after_direct_write (static_cast(len)); + return len; + } + + size_t plen; + const char *v = lookup_system_property (name, plen); + if (v == nullptr) + return len; + + value.assign (v, plen); + return Helpers::add_with_overflow_check (plen, 0); +} + +auto +AndroidSystem::get_max_gref_count_from_system () noexcept -> long +{ + long max; + + if (running_in_emulator) { + max = 2000; + } else { + max = 51200; + } + + dynamic_local_string override; + if (monodroid_get_system_property (Constants::DEBUG_MONO_MAX_GREFC, override) > 0) { + char *e; + max = strtol (override.get (), &e, 10); + switch (*e) { + case 'k': + e++; + max *= 1000; + break; + case 'm': + e++; + max *= 1000000; + break; + } + + if (max < 0) { + max = std::numeric_limits::max (); + } + + if (*e) { + log_warn (LOG_GC, "Unsupported '{}' value '{}'.", Constants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); + } + + log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); + } + + return max; +} diff --git a/src/native-clr/shared/CMakeLists.txt b/src/native-clr/shared/CMakeLists.txt new file mode 100644 index 00000000000..9c176e6ac65 --- /dev/null +++ b/src/native-clr/shared/CMakeLists.txt @@ -0,0 +1,59 @@ +set(LIB_NAME xa-shared-bits-clr) +set(LIB_ALIAS xa::shared-clr) + +set(XA_SHARED_SOURCES + helpers.cc + log_functions.cc +) +add_clang_check_sources("${XA_SHARED_SOURCES};") + +add_library( + ${LIB_NAME} + STATIC + ${XA_SHARED_SOURCES} + ${XA_SHARED_CXX_ABI_SOURCES} +) +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +set_static_library_suffix(${LIB_NAME}) + +macro(lib_target_options TARGET_NAME) + target_include_directories( + ${TARGET_NAME} + PUBLIC + "$" + "$" + ) + + target_link_libraries( + ${TARGET_NAME} + PUBLIC + xa::java-interop-clr + -llog + ) + + target_include_directories( + ${TARGET_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} + ) + + target_compile_options( + ${TARGET_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} + ) + + if(DEBUG_BUILD) + set_target_properties( + ${TARGET_NAME} + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) + endif() + + xa_add_compile_definitions(${TARGET_NAME}) + xa_add_include_directories(${TARGET_NAME}) +endmacro() + +lib_target_options(${LIB_NAME}) diff --git a/src/native-clr/shared/helpers.cc b/src/native-clr/shared/helpers.cc new file mode 100644 index 00000000000..59697e7d257 --- /dev/null +++ b/src/native-clr/shared/helpers.cc @@ -0,0 +1,46 @@ +#include +#include +#include + +#include +#include + +using namespace xamarin::android; + +[[noreturn]] void +Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept +{ + // Log it, but also... + log_fatal (category, "{}", message); + + // ...let android include it in the tombstone, debuggerd output, stack trace etc + android_set_abort_message (message); + + if (log_location) { + // We don't want to log the full path, just the file name. libc++ uses full file path here. + const char *file_name = sloc.file_name (); + const char *last_path_sep = strrchr (file_name, '/'); + + if (last_path_sep == nullptr) [[unlikely]] { + // In case we were built on Windows + last_path_sep = strrchr (file_name, '\\'); + } + + if (last_path_sep != nullptr) [[likely]] { + last_path_sep++; + if (*last_path_sep != '\0') [[unlikely]] { + file_name = last_path_sep; + } + } + + log_fatal ( + category, + "Abort at {}:{}:{} ('%s')", + file_name, + sloc.line (), + sloc.column (), + sloc.function_name () + ); + } + std::abort (); +} diff --git a/src/native-clr/shared/log_functions.cc b/src/native-clr/shared/log_functions.cc new file mode 100644 index 00000000000..acd5e705c06 --- /dev/null +++ b/src/native-clr/shared/log_functions.cc @@ -0,0 +1,131 @@ +#include +#include +#include +#include + +#include + +#include "java-interop-logger.h" +#include +#include + +using namespace xamarin::android; + +namespace { + // Must match the same ordering as LogCategories + constexpr std::array log_names = { + Constants::LOG_CATEGORY_NAME_NONE, + Constants::LOG_CATEGORY_NAME_MONODROID, + Constants::LOG_CATEGORY_NAME_MONODROID_ASSEMBLY, + Constants::LOG_CATEGORY_NAME_MONODROID_DEBUG, + Constants::LOG_CATEGORY_NAME_MONODROID_GC, + Constants::LOG_CATEGORY_NAME_MONODROID_GREF, + Constants::LOG_CATEGORY_NAME_MONODROID_LREF, + Constants::LOG_CATEGORY_NAME_MONODROID_TIMING, + Constants::LOG_CATEGORY_NAME_MONODROID_BUNDLE, + Constants::LOG_CATEGORY_NAME_MONODROID_NETWORK, + Constants::LOG_CATEGORY_NAME_MONODROID_NETLINK, + Constants::LOG_CATEGORY_NAME_ERROR, + }; + + [[gnu::always_inline]] + constexpr auto category_name (int value) noexcept -> const char* + { + if (value == 0) { + return log_names[0].data (); + } + + // ffs(value) returns index of lowest bit set in `value` + return log_names [static_cast(ffs (value))].data (); + } + + constexpr android_LogPriority DEFAULT_PRIORITY = ANDROID_LOG_INFO; + + // relies on the fact that the LogLevel enum has sequential values + 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 + }; + + constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1; +} + +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) != category) { + 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) != category) { + return; + } + + DO_LOG (ANDROID_LOG_DEBUG, category, format, args); +} + +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-clr/startup/CMakeLists.txt b/src/native-clr/startup/CMakeLists.txt new file mode 100644 index 00000000000..773eda8cf3a --- /dev/null +++ b/src/native-clr/startup/CMakeLists.txt @@ -0,0 +1,52 @@ +set(LIB_NAME xamarin-startup-clr) +set(LIB_ALIAS xa::xamarin-startup-clr) + +set(XAMARIN_STARTUP_SOURCES + zip.cc +) +add_clang_check_sources("${XAMARIN_STARTUP_SOURCES}") + +add_library( + ${LIB_NAME} + SHARED + ${XAMARIN_STARTUP_SOURCES} +) + +add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) + +target_include_directories( + ${LIB_NAME} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} +) + +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 +) + +target_link_directories( + ${LIB_NAME} + PRIVATE + ${NET_RUNTIME_DIR}/native-clr +) + +target_link_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} +) + +target_link_libraries( + ${LIB_NAME} + PRIVATE + xa::shared-clr + -llog +) + +xa_add_compile_definitions(${LIB_NAME}) +xa_add_include_directories(${LIB_NAME}) diff --git a/src/native-clr/startup/zip.cc b/src/native-clr/startup/zip.cc new file mode 100644 index 00000000000..cef57b26618 --- /dev/null +++ b/src/native-clr/startup/zip.cc @@ -0,0 +1,3 @@ +#include + +using namespace xamarin::android; diff --git a/src/native-clr/xamarin-app-stub/CMakeLists.txt b/src/native-clr/xamarin-app-stub/CMakeLists.txt new file mode 100644 index 00000000000..d23328f9ce7 --- /dev/null +++ b/src/native-clr/xamarin-app-stub/CMakeLists.txt @@ -0,0 +1,54 @@ +set(LIB_NAME xamarin-app-clr) +set(LIB_ALIAS xa::xamarin-app-clr) + +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} + SYSTEM PRIVATE + ${SYSROOT_CXX_INCLUDE_DIR} +) + +target_compile_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_ARGS} +) + +target_link_options( + ${LIB_NAME} + PRIVATE + ${XA_COMMON_CXX_LINKER_ARGS} + ${XA_CXX_DSO_LINKER_ARGS} +) + +target_link_libraries( + ${LIB_NAME} + PRIVATE + ${SHARED_LIB_NAME} +) + +if(DEBUG_BUILD) + set(LIB_SUBDIR "Debug") +else() + set(LIB_SUBDIR "Release") +endif() + +set_target_properties( + ${LIB_NAME} + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIB_SUBDIR}" +) + +xa_add_compile_definitions(${LIB_NAME}) +xa_add_include_directories(${LIB_NAME}) diff --git a/src/native-clr/xamarin-app-stub/application_dso_stub.cc b/src/native-clr/xamarin-app-stub/application_dso_stub.cc new file mode 100644 index 00000000000..e9a8bf35235 --- /dev/null +++ b/src/native-clr/xamarin-app-stub/application_dso_stub.cc @@ -0,0 +1,297 @@ +#include +#include + +#include +#include + +// This file MUST have "valid" values everywhere - the DSO it is compiled into is loaded by the +// designer on desktop. +const uint64_t format_tag = FORMAT_TAG; + +#if defined (DEBUG) +static TypeMapEntry java_to_managed[] = {}; + +static TypeMapEntry managed_to_java[] = {}; + +// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs +const TypeMap type_map = { + 0, + nullptr, + nullptr, + java_to_managed, + managed_to_java +}; +#else +const uint32_t map_module_count = 0; +const uint32_t java_type_count = 0; +const char* const java_type_names[] = {}; + +TypeMapModule map_modules[] = {}; +const TypeMapJava map_java[] = {}; +const xamarin::android::hash_t map_java_hashes[] = {}; +#endif + +CompressedAssemblies compressed_assemblies = { + .count = 0, + .descriptors = nullptr, +}; + +// +// Config settings below **must** be valid for Desktop builds as the default `libxamarin-app.{dll,dylib,so}` is used by +// the Designer +// +constexpr char android_package_name[] = "com.xamarin.test"; +const ApplicationConfig application_config = { + .uses_assembly_preload = false, + .jni_add_native_method_registration_attribute_present = false, + .have_runtime_config_blob = false, + .marshal_methods_enabled = false, + .ignore_split_configs = false, + .package_naming_policy = 0, + .environment_variable_count = 0, + .system_property_count = 0, + .number_of_assemblies_in_apk = 2, + .bundled_assembly_name_width = 0, + .number_of_dso_cache_entries = 2, + .number_of_shared_libraries = 2, + .android_runtime_jnienv_class_token = 1, + .jnienv_initialize_method_token = 2, + .jnienv_registerjninatives_method_token = 3, + .jni_remapping_replacement_type_count = 2, + .jni_remapping_replacement_method_index_entry_count = 2, + .android_package_name = android_package_name, +}; + +const char* const app_environment_variables[] = {}; +const char* const app_system_properties[] = {}; + +static constexpr size_t AssemblyNameWidth = 128uz; + +static char first_assembly_name[AssemblyNameWidth]; +static char second_assembly_name[AssemblyNameWidth]; + +XamarinAndroidBundledAssembly bundled_assemblies[] = { + { + .file_fd = -1, + .file_name = nullptr, + .data_offset = 0, + .data_size = 0, + .data = nullptr, + .name_length = 0, + .name = first_assembly_name, + }, + + { + .file_fd = -1, + .file_name = nullptr, + .data_offset = 0, + .data_size = 0, + .data = nullptr, + .name_length = 0, + .name = second_assembly_name, + }, +}; + +AssemblyStoreSingleAssemblyRuntimeData assembly_store_bundled_assemblies[] = { + { + .image_data = nullptr, + .debug_info_data = nullptr, + .config_data = nullptr, + .descriptor = nullptr, + }, + + { + .image_data = nullptr, + .debug_info_data = nullptr, + .config_data = nullptr, + .descriptor = nullptr, + }, +}; + +AssemblyStoreRuntimeData assembly_store = { + .data_start = nullptr, + .assembly_count = 0, + .index_entry_count = 0, + .assemblies = nullptr, +}; + +constexpr char fake_dso_name[] = "libaot-Some.Assembly.dll.so"; +constexpr char fake_dso_name2[] = "libaot-Another.Assembly.dll.so"; + +DSOCacheEntry dso_cache[] = { + { + .hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), + .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), + .ignore = true, + .name = fake_dso_name, + .handle = nullptr, + }, + + { + .hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), + .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), + .ignore = true, + .name = fake_dso_name2, + .handle = nullptr, + }, +}; + +DSOCacheEntry aot_dso_cache[] = { + { + .hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), + .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), + .ignore = true, + .name = fake_dso_name, + .handle = nullptr, + }, + + { + .hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), + .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), + .ignore = true, + .name = fake_dso_name2, + .handle = nullptr, + }, +}; + +DSOApkEntry dso_apk_entries[2] {}; + +// +// Support for marshal methods +// +#if defined (RELEASE) +void* assembly_image_cache[] = { + nullptr, + nullptr, + +}; + +// Each element contains an index into `assembly_image_cache` +const uint32_t assembly_image_cache_indices[] = { + 0, + 1, + 1, + 1, +}; + +// hashes point to indices in `assembly_image_cache_indices` +const xamarin::android::hash_t assembly_image_cache_hashes[] = { + 0, + 1, + 2, + 3, +}; + +uint32_t marshal_methods_number_of_classes = 2; +MarshalMethodsManagedClass marshal_methods_class_cache[] = { + { + .token = 0, + .klass = nullptr, + }, + + { + .token = 0, + .klass = nullptr, + }, +}; + +const char* const mm_class_names[2] = { + "one", + "two", +}; + +const MarshalMethodName mm_method_names[] = { + { + .id = 1, + .name = "one", + }, + + { + .id = 2, + .name = "two", + }, +}; + +void xamarin_app_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] get_function_pointer_fn fn) noexcept +{ + // Dummy +} +#endif // def RELEASE + +static const JniRemappingIndexMethodEntry some_java_type_one_methods[] = { + { + .name = { + .length = 15, + .str = "old_method_name", + }, + + .signature = { + .length = 0, + .str = nullptr, + }, + + .replacement = { + .target_type = "some/java/target_type_one", + .target_name = "new_method_name", + .is_static = false, + } + }, +}; + +static const JniRemappingIndexMethodEntry some_java_type_two_methods[] = { + { + .name = { + .length = 15, + .str = "old_method_name", + }, + + .signature = { + .length = 28, + .str = "(IILandroid/content/Intent;)", + }, + + .replacement = { + .target_type = "some/java/target_type_two", + .target_name = "new_method_name", + .is_static = true, + } + }, +}; + +const JniRemappingIndexTypeEntry jni_remapping_method_replacement_index[] = { + { + .name = { + .length = 18, + .str = "some/java/type_one", + }, + .method_count = 1, + .methods = some_java_type_one_methods, + }, + + { + .name = { + .length = 18, + .str = "some/java/type_two", + }, + .method_count = 1, + .methods = some_java_type_two_methods, + }, +}; + +const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[] = { + { + .name = { + .length = 14, + .str = "some/java/type", + }, + .replacement = "another/java/type", + }, + + { + .name = { + .length = 20, + .str = "some/other/java/type", + }, + .replacement = "another/replacement/java/type", + }, +}; From 8ec22aab9b68eb4871939fb951ac4979bf4d88a2 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 3 Dec 2024 13:38:51 +0100 Subject: [PATCH 024/143] Address feedback --- src/native/mono/shared/cpp-util.hh | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index f2f03b9d5b6..abbaa95bb79 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -33,6 +33,50 @@ namespace xamarin::android::detail { va_end (ap); return ret == -1 ? "Out of memory" : message; } + + [[gnu::always_inline]] + static inline std::string get_function_name (const char *signature) + { + using std::operator""sv; + + std::string_view sig { signature }; + if (sig.length () == 0) { + return ""; + } + + auto splitSignature = sig | std::views::split ("::"sv) | std::ranges::to> (); + + std::string ret; + if (splitSignature.size () > 1) { + ret.append (splitSignature [splitSignature.size () - 2]); + ret.append ("::"sv); + } + std::string_view func_name { splitSignature[splitSignature.size () - 1] }; + std::string_view::size_type args_pos = func_name.find ('('); + std::string_view::size_type name_start_pos = func_name.find (' '); + + if (name_start_pos == std::string_view::npos) { + name_start_pos = 0; + } else { + name_start_pos++; // point to after the space which separates return type from name + if (name_start_pos >= func_name.length ()) [[unlikely]] { + name_start_pos = 0; + } + } + + if (args_pos == std::string_view::npos) { + ret.append (func_name.substr (name_start_pos)); + } else { + // If there's a snafu with positions, start from 0 + if (name_start_pos >= args_pos || name_start_pos > func_name.length ()) [[unlikely]] { + name_start_pos = 0; + } + + ret.append (func_name.substr (name_start_pos, args_pos - name_start_pos)); + } + + return ret; + } } template F> @@ -66,7 +110,13 @@ abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_loc { abort_unless ( ptr != nullptr, - [&ptr_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", ptr_name); }, + [&ptr_name, &sloc] { + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a valid pointer", + xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), + ptr_name + ); + }, sloc ); } @@ -77,7 +127,13 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l { abort_unless ( arg > 0, - [&arg_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", arg_name); }, + [&arg_name, &sloc] { + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a valid pointer", + xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), + arg_name + ); + }, sloc ); } From 8a08bc131adc34b3bcfb52cf37bcb3c6da28adcd Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 3 Dec 2024 19:47:42 +0100 Subject: [PATCH 025/143] First packaging steps + Java startup code changes --- .../Microsoft.Android.Runtime.proj | 30 +++++-------------- .../installers/create-installers.targets | 4 +++ ...oft.Android.Sdk.AssemblyResolution.targets | 4 +++ .../Tasks/ProcessNativeLibraries.cs | 15 ++++++---- .../Xamarin.Android.Common.targets | 7 ++++- .../java/mono/android/MonoPackageManager.java | 2 +- .../mono/android/clr/MonoPackageManager.java | 23 +++++--------- src/native-clr/host/host-jni.cc | 8 ++--- src/native-clr/include/host/host-jni.hh | 4 +-- src/native-clr/java-interop/CMakeLists.txt | 2 +- src/native-clr/libnet-android.map.txt | 2 +- src/native-clr/runtime-base/CMakeLists.txt | 10 +------ src/native-clr/runtime-base/android-system.cc | 14 ++++----- src/native-clr/shared/CMakeLists.txt | 11 +------ src/native-clr/startup/CMakeLists.txt | 5 ++-- 15 files changed, 58 insertions(+), 83 deletions(-) diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 6d1820cff7c..fa1aec12a45 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -45,29 +45,13 @@ projects that use the Microsoft.Android framework in .NET 6+. Condition=" '$(AndroidRuntime)' == 'NativeAOT' " /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\Mono.Android.Export.dll" /> - - - - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.debug.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.debug.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so" /> - - - - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.debug.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.release.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libxamarin-debug-app-helper.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libxamarin-native-tracing.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libunwind_xamarin.a" /> - - - - - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.debug.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.debug.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.release.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.release.so" /> + <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-debug-app-helper.so" /> + <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-native-tracing.so" /> + <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libunwind_xamarin.a" /> diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index d7ed385f907..8f5b8b1e9a8 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -133,6 +133,10 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_net6.jar" ExcludeFromLegacy="true" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_net6.dex" ExcludeFromLegacy="true" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_net6.dex" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_clr.jar" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_clr.jar" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_clr.dex" ExcludeFromLegacy="true" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_clr.dex" ExcludeFromLegacy="true" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)manifestmerger.jar" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)proguard-android.txt" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)protobuf-net.dll" /> diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index afda07d8c7d..5ac211718c4 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 @@ -235,6 +235,10 @@ _ResolveAssemblies MSBuild target. <_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' != 'True' " Include="libnet-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' != 'True' " Include="libnet-android.release" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' == 'True' " Include="libmono-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' == 'True' " Include="libmono-android.release" /> - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_net6.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_net6.dex + + + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_clr.jar + <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_clr.dex + diff --git a/src/java-runtime/java/mono/android/MonoPackageManager.java b/src/java-runtime/java/mono/android/MonoPackageManager.java index 1c0487e046f..9878c0d8e6c 100644 --- a/src/java-runtime/java/mono/android/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/MonoPackageManager.java @@ -65,7 +65,7 @@ public static void LoadApplication (Context context) } // - // Should the order change here, src/monodroid/jni/SharedConstants.hh must be updated accordingly + // Should the order change here, src/native/runtime-base/shared-constants.hh must be updated accordingly // String[] appDirs = new String[] {filesDir, cacheDir, dataDir}; boolean haveSplitApks = runtimePackage.splitSourceDirs != null && runtimePackage.splitSourceDirs.length > 0; diff --git a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java index 4cfa0ea2169..6ece4b145a0 100644 --- a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java @@ -18,29 +18,19 @@ import mono.android.Runtime; import mono.android.DebugRuntime; import mono.android.BuildConfig; -import net.dot.android.ApplicationRegistration; public class MonoPackageManager { static Object lock = new Object (); static boolean initialized; - public static void LoadApplication (Context context) + static android.content.Context Context; + + public static void LoadApplication (Context context, ApplicationInfo runtimePackage, String[] apks) { synchronized (lock) { - android.content.pm.ApplicationInfo runtimePackage = context.getApplicationInfo (); - String[] apks = null; - String[] splitApks = runtimePackage.splitSourceDirs; - if (splitApks != null && splitApks.length > 0) { - apks = new String[splitApks.length + 1]; - apks [0] = runtimePackage.sourceDir; - System.arraycopy (splitApks, 0, apks, 1, splitApks.length); - } else { - apks = new String[] { runtimePackage.sourceDir }; - } - if (context instanceof android.app.Application) { - ApplicationRegistration.Context = context; + Context = context; } if (!initialized) { android.content.IntentFilter timezoneChangedFilter = new android.content.IntentFilter ( @@ -64,7 +54,7 @@ public static void LoadApplication (Context context) } // - // Should the order change here, src/native/clr/include/constants.hh must be updated accordingly + // Should the order change here, src/native-clr/include/constants.hh must be updated accordingly // String[] appDirs = new String[] {filesDir, cacheDir, dataDir}; boolean haveSplitApks = runtimePackage.splitSourceDirs != null && runtimePackage.splitSourceDirs.length > 0; @@ -83,7 +73,8 @@ public static void LoadApplication (Context context) haveSplitApks ); - ApplicationRegistration.registerApplications (); + mono.android.app.ApplicationRegistration.registerApplications (); + initialized = true; } } diff --git a/src/native-clr/host/host-jni.cc b/src/native-clr/host/host-jni.cc index 3e9af6e868a..33b9180eff3 100644 --- a/src/native-clr/host/host-jni.cc +++ b/src/native-clr/host/host-jni.cc @@ -25,10 +25,10 @@ JNICALL Java_mono_android_Runtime_register (JNIEnv *env, [[maybe_unused]] jclass } JNIEXPORT void JNICALL -Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, - jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, - jobjectArray assembliesJava, jboolean isEmulator, - jboolean haveSplitApks) +Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, + jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, + jobjectArray assembliesJava, jboolean isEmulator, + jboolean haveSplitApks) { } diff --git a/src/native-clr/include/host/host-jni.hh b/src/native-clr/include/host/host-jni.hh index 2104c2b1846..4904644ebd8 100644 --- a/src/native-clr/include/host/host-jni.hh +++ b/src/native-clr/include/host/host-jni.hh @@ -19,10 +19,10 @@ extern "C" { /* * Class: mono_android_Runtime - * Method: init + * Method: initInternal * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;ILjava/lang/ClassLoader;[Ljava/lang/String;IZZ)V */ - JNIEXPORT void JNICALL Java_mono_android_Runtime_init (JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jint, jobject, jobjectArray, jboolean, jboolean); + JNIEXPORT void JNICALL Java_mono_android_Runtime_initInternal (JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jint, jobject, jobjectArray, jboolean, jboolean); /* * Class: mono_android_Runtime diff --git a/src/native-clr/java-interop/CMakeLists.txt b/src/native-clr/java-interop/CMakeLists.txt index 702401df40c..a731f0110e0 100644 --- a/src/native-clr/java-interop/CMakeLists.txt +++ b/src/native-clr/java-interop/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIB_NAME xa-java-interop-clr) +set(LIB_NAME xa-java-interop) set(LIB_ALIAS xa::java-interop-clr) set(JAVA_INTEROP_SOURCES diff --git a/src/native-clr/libnet-android.map.txt b/src/native-clr/libnet-android.map.txt index f7e3c7c9fdf..9c8a580bc34 100644 --- a/src/native-clr/libnet-android.map.txt +++ b/src/native-clr/libnet-android.map.txt @@ -2,7 +2,7 @@ LIBNET_ANDROID { global: JNI_OnLoad; Java_mono_android_Runtime_dumpTimingData; - Java_mono_android_Runtime_init; + Java_mono_android_Runtime_initInternal; Java_mono_android_Runtime_notifyTimeZoneChanged; Java_mono_android_Runtime_propagateUncaughtException; Java_mono_android_Runtime_register; diff --git a/src/native-clr/runtime-base/CMakeLists.txt b/src/native-clr/runtime-base/CMakeLists.txt index 7e42498b5e4..6f2c07bb299 100644 --- a/src/native-clr/runtime-base/CMakeLists.txt +++ b/src/native-clr/runtime-base/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIB_NAME runtime-base-clr) +set(LIB_NAME runtime-base) set(LIB_ALIAS xa::runtime-base-clr) set(XA_RUNTIME_BASE_SOURCES @@ -43,13 +43,5 @@ target_link_libraries( xa::xamarin-app-clr ) -if(DEBUG_BUILD) - set_target_properties( - ${LIB_NAME} - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - ) -endif() - xa_add_compile_definitions(${LIB_NAME}) xa_add_include_directories(${LIB_NAME}) diff --git a/src/native-clr/runtime-base/android-system.cc b/src/native-clr/runtime-base/android-system.cc index fcf6a82b640..75dc394cdbd 100644 --- a/src/native-clr/runtime-base/android-system.cc +++ b/src/native-clr/runtime-base/android-system.cc @@ -11,13 +11,13 @@ auto AndroidSystem::lookup_system_property (std::string_view const& name, size_t &value_len) noexcept -> const char* { value_len = 0; -#if defined (DEBUG) - BundledProperty *p = lookup_system_property (name); - if (p != nullptr) { - value_len = p->value_len; - return p->name; - } -#endif // DEBUG || !ANDROID +// #if defined (DEBUG) +// BundledProperty *p = lookup_system_property (name); +// if (p != nullptr) { +// value_len = p->value_len; +// return p->name; +// } +// #endif // DEBUG || !ANDROID if (application_config.system_property_count == 0) { return nullptr; diff --git a/src/native-clr/shared/CMakeLists.txt b/src/native-clr/shared/CMakeLists.txt index 9c176e6ac65..c1a85951663 100644 --- a/src/native-clr/shared/CMakeLists.txt +++ b/src/native-clr/shared/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIB_NAME xa-shared-bits-clr) +set(LIB_NAME xa-shared-bits) set(LIB_ALIAS xa::shared-clr) set(XA_SHARED_SOURCES @@ -11,7 +11,6 @@ add_library( ${LIB_NAME} STATIC ${XA_SHARED_SOURCES} - ${XA_SHARED_CXX_ABI_SOURCES} ) add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) @@ -44,14 +43,6 @@ macro(lib_target_options TARGET_NAME) ${XA_COMMON_CXX_ARGS} ) - if(DEBUG_BUILD) - set_target_properties( - ${TARGET_NAME} - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - ) - endif() - xa_add_compile_definitions(${TARGET_NAME}) xa_add_include_directories(${TARGET_NAME}) endmacro() diff --git a/src/native-clr/startup/CMakeLists.txt b/src/native-clr/startup/CMakeLists.txt index 773eda8cf3a..2f6951c6275 100644 --- a/src/native-clr/startup/CMakeLists.txt +++ b/src/native-clr/startup/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIB_NAME xamarin-startup-clr) +set(LIB_NAME xamarin-startup) set(LIB_ALIAS xa::xamarin-startup-clr) set(XAMARIN_STARTUP_SOURCES @@ -8,11 +8,12 @@ add_clang_check_sources("${XAMARIN_STARTUP_SOURCES}") add_library( ${LIB_NAME} - SHARED + STATIC ${XAMARIN_STARTUP_SOURCES} ) add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) +set_static_library_suffix(${LIB_NAME}) target_include_directories( ${LIB_NAME} From 1d05f4c4c04dbd0ebb0ca6fa211fbefcdfc1c518 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 3 Dec 2024 22:14:38 +0100 Subject: [PATCH 026/143] Build deps + application config for CLR --- .../Tasks/GeneratePackageManagerJava.cs | 75 +++++--- .../Tasks/LinkApplicationSharedLibraries.cs | 8 +- .../Utilities/ApplicationConfigCLR.cs | 4 +- ...icationConfigNativeAssemblyGeneratorCLR.cs | 161 +----------------- .../Xamarin.Android.Common.targets | 12 +- src/native-clr/host/host-jni.cc | 3 + src/native-clr/host/host.cc | 3 + src/native-clr/include/shared/log_types.hh | 6 + src/native-clr/java-interop/CMakeLists.txt | 8 - src/native-clr/lz4/CMakeLists.txt | 4 +- src/native-clr/native-clr.targets | 11 ++ src/native-clr/runtime-base/android-system.cc | 5 +- 12 files changed, 101 insertions(+), 199 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index d58e7f70e79..97fde5d1e3b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -64,6 +64,9 @@ public class GeneratePackageManagerJava : AndroidTask [Required] public bool EnablePreloadAssembliesDefault { get; set; } + [Required] + public bool TargetsCLR { get; set; } + public bool EnableMarshalMethods { get; set; } public string RuntimeConfigBinFilePath { get; set; } public string BoundExceptionType { get; set; } @@ -319,31 +322,53 @@ void AddEnvironment () bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); - var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { - UsesMonoAOT = usesMonoAOT, - UsesMonoLLVM = EnableLLVM, - UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, - MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), - AotEnableLazyLoad = AndroidAotEnableLazyLoad, - AndroidPackageName = AndroidPackageName, - BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, - PackageNamingPolicy = pnp, - BoundExceptionType = boundExceptionType, - JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, - HaveRuntimeConfigBlob = haveRuntimeConfigBlob, - NumberOfAssembliesInApk = assemblyCount, - BundledAssemblyNameWidth = assemblyNameWidth, - MonoComponents = (MonoComponent)monoComponents, - NativeLibraries = uniqueNativeLibraries, - HaveAssemblyStore = UseAssemblyStore, - AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, - JNIEnvInitializeToken = jnienv_initialize_method_token, - JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, - JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, - JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, - MarshalMethodsEnabled = EnableMarshalMethods, - IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), - }; + LLVMIR.LlvmIrComposer appConfigAsmGen; + + if (TargetsCLR) { + appConfigAsmGen = new ApplicationConfigNativeAssemblyGeneratorCLR (environmentVariables, systemProperties, Log) { + UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, + AndroidPackageName = AndroidPackageName, + PackageNamingPolicy = pnp, + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + HaveRuntimeConfigBlob = haveRuntimeConfigBlob, + NumberOfAssembliesInApk = assemblyCount, + BundledAssemblyNameWidth = assemblyNameWidth, + NativeLibraries = uniqueNativeLibraries, + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, + JNIEnvInitializeToken = jnienv_initialize_method_token, + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, + MarshalMethodsEnabled = EnableMarshalMethods, + IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + }; + } else { + appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { + UsesMonoAOT = usesMonoAOT, + UsesMonoLLVM = EnableLLVM, + UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, + MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), + AotEnableLazyLoad = AndroidAotEnableLazyLoad, + AndroidPackageName = AndroidPackageName, + BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, + PackageNamingPolicy = pnp, + BoundExceptionType = boundExceptionType, + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + HaveRuntimeConfigBlob = haveRuntimeConfigBlob, + NumberOfAssembliesInApk = assemblyCount, + BundledAssemblyNameWidth = assemblyNameWidth, + MonoComponents = (MonoComponent)monoComponents, + NativeLibraries = uniqueNativeLibraries, + HaveAssemblyStore = UseAssemblyStore, + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, + JNIEnvInitializeToken = jnienv_initialize_method_token, + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, + MarshalMethodsEnabled = EnableMarshalMethods, + IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + }; + } LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct (); foreach (string abi in SupportedAbis) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 6fb2dac8967..4d9aef3bcd4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -43,6 +43,9 @@ sealed class InputFiles [Required] public string AndroidBinUtilsDirectory { get; set; } + [Required] + public bool TargetsCLR { get; set; } + public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment64Bit; public override System.Threading.Tasks.Task RunTaskAsync () @@ -123,11 +126,12 @@ IEnumerable GetLinkerConfigs () abis [abi] = GatherFilesForABI (item.ItemSpec, abi, ObjectFiles, runtimeNativeLibsDir, runtimeNativeLibStubsDir); } - const string commonLinkerArgs = + string soname = TargetsCLR ? "libxamarin-app-clr.so" : "libxamarin-app.so"; + string commonLinkerArgs = "--shared " + "--allow-shlib-undefined " + "--export-dynamic " + - "-soname libxamarin-app.so " + + $"-soname {soname} " + "-z relro " + "-z noexecstack " + "--enable-new-dtags " + diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs index 249efc6c031..0e5593bb363 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs @@ -3,7 +3,7 @@ namespace Xamarin.Android.Tasks; // Declaration order of fields and their types must correspond *exactly* to that in -// src/native/clr/xamarin-app-stub/xamarin-app.hh ApplicationConfig structure +// src/native-clr/xamarin-app-stub/xamarin-app.hh ApplicationConfig structure // // Type mappings: // @@ -26,9 +26,9 @@ sealed class ApplicationConfigCLR { public bool uses_assembly_preload; public bool jni_add_native_method_registration_attribute_present; + public bool have_runtime_config_blob; public bool marshal_methods_enabled; public bool ignore_split_configs; - public uint number_of_runtime_properties; public uint package_naming_policy; public uint environment_variable_count; public uint system_property_count; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index 92440adfc42..24ec67e9e73 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -12,11 +12,6 @@ namespace Xamarin.Android.Tasks; class ApplicationConfigNativeAssemblyGeneratorCLR : LlvmIrComposer { - // From host_runtime_contract.h in dotnet/runtime - const string HOST_PROPERTY_RUNTIME_CONTRACT = "HOST_RUNTIME_CONTRACT"; - const string HOST_PROPERTY_BUNDLE_PROBE = "BUNDLE_PROBE"; - const string HOST_PROPERTY_PINVOKE_OVERRIDE = "PINVOKE_OVERRIDE"; - sealed class DSOCacheEntryContextDataProvider : NativeAssemblerStructContextDataProvider { public override string GetComment (object data, string fieldName) @@ -34,11 +29,6 @@ public override string GetComment (object data, string fieldName) } } - // Disable "Field 'X' is never assigned to, and will always have its default value Y" - // Classes below are used in native code generation, thus all the fields must be present - // but they aren't always assigned values (which is fine). - #pragma warning disable CS0649 - // Order of fields and their type must correspond *exactly* (with exception of the // ignored managed members) to that in // src/monodroid/jni/xamarin-app.hh DSOCacheEntry structure @@ -99,7 +89,7 @@ sealed class AssemblyStoreSingleAssemblyRuntimeData } // Order of fields and their type must correspond *exactly* to that in - // src/native/clr/include/xamarin-app.hh AssemblyStoreRuntimeData structure + // src/monodroid/jni/xamarin-app.hh AssemblyStoreRuntimeData structure sealed class AssemblyStoreRuntimeData { [NativePointer (IsNull = true)] @@ -111,27 +101,6 @@ sealed class AssemblyStoreRuntimeData public AssemblyStoreAssemblyDescriptor assemblies; } - // Order of fields and their types must correspond *exactly* to that in - // src/native/clr/include/xamarin-app.hh RuntimeProperty structure - sealed class RuntimeProperty - { - public string key; - public string value; - public uint value_size; - } - - // Order of fields and their types must correspond *exactly* to that in - // src/native/clr/include/xamarin-app.hh RuntimePropertyIndexEntry structure - sealed class RuntimePropertyIndexEntry - { - [NativeAssembler (Ignore = true)] - public string HashedKey; - - [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] - public ulong key_hash; - public uint index; - } - sealed class XamarinAndroidBundledAssemblyContextDataProvider : NativeAssemblerStructContextDataProvider { public override ulong GetBufferSize (object data, string fieldName) @@ -168,20 +137,16 @@ sealed class XamarinAndroidBundledAssembly [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToPreAllocatedBuffer = true)] public string name; } -#pragma warning restore CS0649 // Keep in sync with FORMAT_TAG in src/monodroid/jni/xamarin-app.hh const ulong FORMAT_TAG = 0x00025E6972616D58; // 'Xmari^XY' where XY is the format version SortedDictionary ? environmentVariables; SortedDictionary ? systemProperties; - SortedDictionary ? runtimeProperties; StructureInstance? application_config; List>? dsoCache; List>? aotDsoCache; List>? xamarinAndroidBundledAssemblies; - List>? runtimePropertiesData; - List>? runtimePropertyIndex; StructureInfo? applicationConfigStructureInfo; StructureInfo? dsoCacheEntryStructureInfo; @@ -189,14 +154,11 @@ sealed class XamarinAndroidBundledAssembly StructureInfo? xamarinAndroidBundledAssemblyStructureInfo; StructureInfo? assemblyStoreSingleAssemblyRuntimeDataStructureinfo; StructureInfo? assemblyStoreRuntimeDataStructureInfo; - StructureInfo? runtimePropertyStructureInfo; - StructureInfo? runtimePropertyIndexEntryStructureInfo; - StructureInfo? hostConfigurationPropertyStructureInfo; - StructureInfo? hostConfigurationPropertiesStructureInfo; public bool UsesAssemblyPreload { get; set; } public string AndroidPackageName { get; set; } public bool JniAddNativeMethodRegistrationAttributePresent { get; set; } + public bool HaveRuntimeConfigBlob { get; set; } public int NumberOfAssembliesInApk { get; set; } public int BundledAssemblyNameWidth { get; set; } // including the trailing NUL public int AndroidRuntimeJNIEnvToken { get; set; } @@ -209,8 +171,7 @@ sealed class XamarinAndroidBundledAssembly public bool MarshalMethodsEnabled { get; set; } public bool IgnoreSplitConfigs { get; set; } - public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary environmentVariables, IDictionary systemProperties, - IDictionary? runtimeProperties, TaskLoggingHelper log) + public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary environmentVariables, IDictionary systemProperties, TaskLoggingHelper log) : base (log) { if (environmentVariables != null) { @@ -220,19 +181,6 @@ public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary if (systemProperties != null) { this.systemProperties = new SortedDictionary (systemProperties, StringComparer.Ordinal); } - - if (runtimeProperties != null) { - this.runtimeProperties = new SortedDictionary (runtimeProperties, StringComparer.Ordinal); - } else { - this.runtimeProperties = new SortedDictionary (StringComparer.Ordinal); - } - - // This will be filled in by the native host. - this.runtimeProperties[HOST_PROPERTY_RUNTIME_CONTRACT] = String.Empty; - - // these mustn't be there, they would break our host contract - this.runtimeProperties.Remove (HOST_PROPERTY_PINVOKE_OVERRIDE); - this.runtimeProperties.Remove (HOST_PROPERTY_BUNDLE_PROBE); } protected override void Construct (LlvmIrModule module) @@ -255,9 +203,9 @@ protected override void Construct (LlvmIrModule module) var app_cfg = new ApplicationConfigCLR { uses_assembly_preload = UsesAssemblyPreload, jni_add_native_method_registration_attribute_present = JniAddNativeMethodRegistrationAttributePresent, + have_runtime_config_blob = HaveRuntimeConfigBlob, marshal_methods_enabled = MarshalMethodsEnabled, ignore_split_configs = IgnoreSplitConfigs, - number_of_runtime_properties = (uint)(runtimeProperties == null ? 0 : runtimeProperties.Count), package_naming_policy = (uint)PackageNamingPolicy, environment_variable_count = (uint)(environmentVariables == null ? 0 : environmentVariables.Count * 2), system_property_count = (uint)(systemProperties == null ? 0 : systemProperties.Count * 2), @@ -302,108 +250,9 @@ protected override void Construct (LlvmIrModule module) }; module.Add (bundled_assemblies); - (runtimePropertiesData, runtimePropertyIndex) = InitRuntimeProperties (); - var runtime_properties = new LlvmIrGlobalVariable (runtimePropertiesData, "runtime_properties", LlvmIrVariableOptions.GlobalConstant) { - Comment = "Runtime config properties", - }; - module.Add (runtime_properties); - - var runtime_property_index = new LlvmIrGlobalVariable (runtimePropertyIndex, "runtime_property_index", LlvmIrVariableOptions.GlobalConstant) { - Comment = "Runtime config property index, sorted on property key hash", - BeforeWriteCallback = HashAndSortRuntimePropertiesIndex, - }; - module.Add (runtime_property_index); - - // HOST_PROPERTY_RUNTIME_CONTRACT will come first, our native runtime requires that since it needs - // to set its value in the values array and we don't want to spend time searching for the index, nor - // we want to add yet another variable storing the index to the entry. KISS. - var runtime_property_names = new List { - HOST_PROPERTY_RUNTIME_CONTRACT, - }; - var runtime_property_values = new List { - null, - }; - - foreach (var kvp in runtimeProperties) { - if (String.Compare (kvp.Key, HOST_PROPERTY_RUNTIME_CONTRACT, StringComparison.Ordinal) == 0) { - continue; - } - runtime_property_names.Add (kvp.Key); - runtime_property_values.Add (kvp.Value); - } - - var init_runtime_property_names = new LlvmIrGlobalVariable (runtime_property_names, "init_runtime_property_names", LlvmIrVariableOptions.GlobalConstant) { - Comment = "Names of properties passed to coreclr_initialize", - }; - module.Add (init_runtime_property_names); - - var init_runtime_property_values = new LlvmIrGlobalVariable (runtime_property_values, "init_runtime_property_values", LlvmIrVariableOptions.GlobalWritable) { - Comment = "Values of properties passed to coreclr_initialize", - }; - module.Add (init_runtime_property_values); - AddAssemblyStores (module); } - void HashAndSortRuntimePropertiesIndex (LlvmIrVariable variable, LlvmIrModuleTarget target, object? state) - { - var index = variable.Value as List>; - if (index == null) { - return; - } - - bool is64Bit = target.Is64Bit; - foreach (StructureInstance instance in index) { - if (instance.Obj == null) { - throw new InvalidOperationException ("Internal error: runtime property index must not contain null entries"); - } - - var entry = instance.Obj as RuntimePropertyIndexEntry; - if (entry == null) { - throw new InvalidOperationException ($"Internal error: runtime property index entry has unexpected type {instance.Obj.GetType ()}"); - } - - entry.key_hash = MonoAndroidHelper.GetXxHash (entry.HashedKey, is64Bit); - }; - - index.Sort ((StructureInstance a, StructureInstance b) => a.Instance.key_hash.CompareTo (b.Instance.key_hash)); - } - - ( - List> runtimeProps, - List> runtimePropsIndex - ) InitRuntimeProperties () - { - var runtimeProps = new List> (); - var runtimePropsIndex = new List> (); - - if (runtimeProperties == null || runtimeProperties.Count == 0) { - return (runtimeProps, runtimePropsIndex); - } - - foreach (var kvp in runtimeProperties) { - string name = kvp.Key; - string value = kvp.Value; - - var prop = new RuntimeProperty { - key = name, - value = value, - - // Includes the terminating NUL - value_size = (uint)(MonoAndroidHelper.Utf8StringToBytes (value).Length + 1), - }; - runtimeProps.Add (new StructureInstance (runtimePropertyStructureInfo, prop)); - - var indexEntry = new RuntimePropertyIndexEntry { - HashedKey = prop.key, - index = (uint)(runtimeProps.Count - 1), - }; - runtimePropsIndex.Add (new StructureInstance (runtimePropertyIndexEntryStructureInfo, indexEntry)); - } - - return (runtimeProps, runtimePropsIndex); - } - void AddAssemblyStores (LlvmIrModule module) { ulong itemCount = (ulong)(NumberOfAssembliesInApk); @@ -535,7 +384,5 @@ void MapStructures (LlvmIrModule module) xamarinAndroidBundledAssemblyStructureInfo = module.MapStructure (); dsoCacheEntryStructureInfo = module.MapStructure (); dsoApkEntryStructureInfo = module.MapStructure (); - runtimePropertyStructureInfo = module.MapStructure (); - runtimePropertyIndexEntryStructureInfo = module.MapStructure (); } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index be0ba2724af..32e17a28607 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1805,6 +1805,7 @@ because xbuild doesn't support framework reference assemblies. UseAssemblyStore="$(AndroidUseAssemblyStore)" EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" + TargetsCLR="$(_AndroidUseCLR)" > @@ -2066,12 +2067,18 @@ because xbuild doesn't support framework reference assemblies. - - + + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app.so"> %(_BuildTargetAbis.Identity) + + + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app-clr.so"> + %(_BuildTargetAbis.Identity) + + diff --git a/src/native-clr/host/host-jni.cc b/src/native-clr/host/host-jni.cc index 33b9180eff3..43775ad0918 100644 --- a/src/native-clr/host/host-jni.cc +++ b/src/native-clr/host/host-jni.cc @@ -1,11 +1,14 @@ #include #include +#include using namespace xamarin::android; JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM *vm, void *reserved) { + log_write (LOG_DEFAULT, LogLevel::Info, "JNI_OnLoad"); + return Host::Java_JNI_OnLoad (vm, reserved); } diff --git a/src/native-clr/host/host.cc b/src/native-clr/host/host.cc index 735ae4dfa60..8ca3f58580c 100644 --- a/src/native-clr/host/host.cc +++ b/src/native-clr/host/host.cc @@ -1,11 +1,14 @@ #include #include #include +#include using namespace xamarin::android; auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint { + log_write (LOG_DEFAULT, LogLevel::Info, "Host init"); + AndroidSystem::init_max_gref_count (); return JNI_VERSION_1_6; } diff --git a/src/native-clr/include/shared/log_types.hh b/src/native-clr/include/shared/log_types.hh index 66b1cae5097..656146ec203 100644 --- a/src/native-clr/include/shared/log_types.hh +++ b/src/native-clr/include/shared/log_types.hh @@ -47,6 +47,12 @@ namespace xamarin::android { // 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; + + [[gnu::always_inline]] + static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept + { + log_write (category, level, message.data ()); + } } template [[gnu::always_inline]] diff --git a/src/native-clr/java-interop/CMakeLists.txt b/src/native-clr/java-interop/CMakeLists.txt index a731f0110e0..24a233e2b80 100644 --- a/src/native-clr/java-interop/CMakeLists.txt +++ b/src/native-clr/java-interop/CMakeLists.txt @@ -39,12 +39,4 @@ target_compile_options( ${XA_COMMON_CXX_ARGS} ) -if(DEBUG_BUILD) - set_target_properties( - ${LIB_NAME} - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - ) -endif() - xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native-clr/lz4/CMakeLists.txt b/src/native-clr/lz4/CMakeLists.txt index 16a35099fd5..140034771f1 100644 --- a/src/native-clr/lz4/CMakeLists.txt +++ b/src/native-clr/lz4/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIB_NAME xa-lz4-clr) +set(LIB_NAME xa-lz4) set(LIB_ALIAS xa::lz4-clr) set(LZ4_SRC_DIR "${EXTERNAL_DIR}/lz4/lib") @@ -16,6 +16,8 @@ add_library( add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) +set_static_library_suffix(${LIB_NAME}) + target_compile_definitions( ${LIB_NAME} PRIVATE diff --git a/src/native-clr/native-clr.targets b/src/native-clr/native-clr.targets index dba9f075f5b..6b5e9260382 100644 --- a/src/native-clr/native-clr.targets +++ b/src/native-clr/native-clr.targets @@ -15,6 +15,11 @@ <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="host\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="runtime-base\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="shared\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="startup\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="xamarin-app-stub\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="java-interop\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="lz4\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> @@ -58,6 +63,12 @@ + <_MonoDroidSources Include="include/**/*.hh" /> + <_MonoDroidSources Include="host/*.cc" /> + <_MonoDroidSources Include="runtime-base/*.cc" /> + <_MonoDroidSources Include="shared/*.cc" /> + <_MonoDroidSources Include="startup/*.cc" /> + <_MonoDroidSources Include="xamarin-app-stub/*.cc" /> <_MonoDroidSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> <_MonoDroidSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> diff --git a/src/native-clr/runtime-base/android-system.cc b/src/native-clr/runtime-base/android-system.cc index 75dc394cdbd..dd381f994a8 100644 --- a/src/native-clr/runtime-base/android-system.cc +++ b/src/native-clr/runtime-base/android-system.cc @@ -86,8 +86,9 @@ auto AndroidSystem::monodroid_get_system_property (std::string_view const& name, size_t plen; const char *v = lookup_system_property (name, plen); - if (v == nullptr) + if (v == nullptr) { return len; + } value.assign (v, plen); return Helpers::add_with_overflow_check (plen, 0); @@ -107,7 +108,7 @@ AndroidSystem::get_max_gref_count_from_system () noexcept -> long dynamic_local_string override; if (monodroid_get_system_property (Constants::DEBUG_MONO_MAX_GREFC, override) > 0) { char *e; - max = strtol (override.get (), &e, 10); + max = strtol (override.get (), &e, 10); switch (*e) { case 'k': e++; From 1147b73bc3795ebdc123212d0348032acc03018d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 4 Dec 2024 19:46:46 +0100 Subject: [PATCH 027/143] Moving on: logging + timing --- src/native-clr/host/host.cc | 18 + src/native-clr/include/constants.hh | 3 + src/native-clr/include/host/host.hh | 14 + src/native-clr/include/runtime-base/logger.hh | 63 +++ .../include/runtime-base/monodroid-state.hh | 21 + .../runtime-base/startup-aware-lock.hh | 40 ++ .../include/runtime-base/strings.hh | 29 ++ .../include/runtime-base/timing-internal.hh | 466 ++++++++++++++++++ src/native-clr/include/runtime-base/timing.hh | 149 ++++++ src/native-clr/include/runtime-base/util.hh | 21 + src/native-clr/runtime-base/CMakeLists.txt | 4 + src/native-clr/runtime-base/logger.cc | 214 ++++++++ .../runtime-base/timing-internal.cc | 83 ++++ src/native-clr/runtime-base/timing.cc | 14 + src/native-clr/runtime-base/util.cc | 45 ++ 15 files changed, 1184 insertions(+) create mode 100644 src/native-clr/include/runtime-base/logger.hh create mode 100644 src/native-clr/include/runtime-base/monodroid-state.hh create mode 100644 src/native-clr/include/runtime-base/startup-aware-lock.hh create mode 100644 src/native-clr/include/runtime-base/timing-internal.hh create mode 100644 src/native-clr/include/runtime-base/timing.hh create mode 100644 src/native-clr/include/runtime-base/util.hh create mode 100644 src/native-clr/runtime-base/logger.cc create mode 100644 src/native-clr/runtime-base/timing-internal.cc create mode 100644 src/native-clr/runtime-base/timing.cc create mode 100644 src/native-clr/runtime-base/util.cc diff --git a/src/native-clr/host/host.cc b/src/native-clr/host/host.cc index 8ca3f58580c..5d3e5830c62 100644 --- a/src/native-clr/host/host.cc +++ b/src/native-clr/host/host.cc @@ -1,10 +1,28 @@ #include #include #include +#include +#include #include using namespace xamarin::android; +void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, + jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, + jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) +{ + Logger::init_logging_categories (); + + // If fast logging is disabled, log messages immediately + FastTiming::initialize ((Logger::log_timing_categories() & LogTimingCategories::FastBare) != LogTimingCategories::FastBare); + + size_t total_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + _timing = std::make_unique (); + total_time_index = internal_timing->start_event (TimingEventKind::TotalRuntimeInit); + } +} + auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint { log_write (LOG_DEFAULT, LogLevel::Info, "Host init"); diff --git a/src/native-clr/include/constants.hh b/src/native-clr/include/constants.hh index e850723ec00..d18ba60e0ed 100644 --- a/src/native-clr/include/constants.hh +++ b/src/native-clr/include/constants.hh @@ -92,5 +92,8 @@ namespace xamarin::android { // 64-bit unsigned or 64-bit signed with sign static constexpr size_t MAX_INTEGER_DIGIT_COUNT_BASE10 = 21uz; static constexpr size_t INTEGER_BASE10_BUFFER_SIZE = MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz; + + // Documented in NDK's comments + static constexpr size_t MAX_LOGCAT_MESSAGE_LENGTH = 1023uz; }; } diff --git a/src/native-clr/include/host/host.hh b/src/native-clr/include/host/host.hh index 03e4186ebae..577dc77f9e3 100644 --- a/src/native-clr/include/host/host.hh +++ b/src/native-clr/include/host/host.hh @@ -1,7 +1,10 @@ #pragma once +#include + #include +#include "../runtime-base/timing.hh" #include "../shared/log_types.hh" namespace xamarin::android { @@ -9,5 +12,16 @@ namespace xamarin::android { { public: static auto Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint; + static void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, + jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, + jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks); + + static auto get_timing () -> Timing* + { + return _timing.get (); + } + + private: + static inline std::unique_ptr _timing{}; }; } diff --git a/src/native-clr/include/runtime-base/logger.hh b/src/native-clr/include/runtime-base/logger.hh new file mode 100644 index 00000000000..45c9e2449bd --- /dev/null +++ b/src/native-clr/include/runtime-base/logger.hh @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include + +#include +#include "strings.hh" + +namespace xamarin::android { + class Logger + { + public: + static void init_logging_categories () noexcept; + static void init_reference_logging (std::string_view const& override_dir) noexcept; + + static auto log_timing_categories () noexcept -> LogTimingCategories + { + return _log_timing_categories; + } + + static void set_gc_spew_enabled (bool yesno) noexcept + { + _gc_spew_enabled = yesno; + } + + static auto gc_spew_enabled () noexcept -> bool + { + return _gc_spew_enabled; + } + + static auto gref_log () -> FILE* + { + return _gref_log; + } + + static auto lref_log () -> FILE* + { + return _lref_log; + } + + static auto gref_to_logcat () -> bool + { + return _gref_to_logcat; + } + + static auto lref_to_logcat () -> bool + { + return _lref_to_logcat; + } + + private: + static bool set_category (std::string_view const& name, string_segment& arg, unsigned int entry, bool arg_starts_with_name = false) noexcept; + + private: + static inline LogTimingCategories _log_timing_categories; + static inline bool _gc_spew_enabled = false; + static inline FILE *_gref_log = nullptr; + static inline FILE *_lref_log = nullptr; + static inline bool _gref_to_logcat = false; + static inline bool _lref_to_logcat = false; + }; +} diff --git a/src/native-clr/include/runtime-base/monodroid-state.hh b/src/native-clr/include/runtime-base/monodroid-state.hh new file mode 100644 index 00000000000..283040d4992 --- /dev/null +++ b/src/native-clr/include/runtime-base/monodroid-state.hh @@ -0,0 +1,21 @@ +#pragma once + +namespace xamarin::android +{ + class MonodroidState + { + public: + static auto is_startup_in_progress () noexcept -> bool + { + return startup_in_progress; + } + + static void mark_startup_done () noexcept + { + startup_in_progress = false; + } + + private: + inline static bool startup_in_progress = true; + }; +} diff --git a/src/native-clr/include/runtime-base/startup-aware-lock.hh b/src/native-clr/include/runtime-base/startup-aware-lock.hh new file mode 100644 index 00000000000..8b869151b61 --- /dev/null +++ b/src/native-clr/include/runtime-base/startup-aware-lock.hh @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "monodroid-state.hh" + +namespace xamarin::android +{ + class StartupAwareLock final + { + public: + explicit StartupAwareLock (std::mutex &m) + : lock (m) + { + if (MonodroidState::is_startup_in_progress ()) { + // During startup we run without threads, do nothing + return; + } + + lock.lock (); + } + + ~StartupAwareLock () + { + if (MonodroidState::is_startup_in_progress ()) { + return; + } + + lock.unlock (); + } + + StartupAwareLock (StartupAwareLock const&) = delete; + StartupAwareLock (StartupAwareLock const&&) = delete; + + StartupAwareLock& operator= (StartupAwareLock const&) = delete; + + private: + std::mutex& lock; + }; +} diff --git a/src/native-clr/include/runtime-base/strings.hh b/src/native-clr/include/runtime-base/strings.hh index c3326e91cc1..cfdb56f53b9 100644 --- a/src/native-clr/include/runtime-base/strings.hh +++ b/src/native-clr/include/runtime-base/strings.hh @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,24 @@ namespace xamarin::android { static constexpr bool BoundsCheck = false; #endif + enum class string_segment_error + { + index_out_of_range, + }; + + static inline auto to_string (string_segment_error error) -> std::string_view const + { + using std::operator""sv; + + switch (error) { + case string_segment_error::index_out_of_range: + return "Index out of range"sv; + + default: + return "Unknown error"sv; + } + } + class string_segment { public: @@ -36,6 +55,16 @@ namespace xamarin::android { return _start; } + [[gnu::always_inline]] + auto at (size_t offset) const noexcept -> std::expected + { + if (offset >= length ()) { + return std::unexpected (string_segment_error::index_out_of_range); + } + + return _start + offset; + } + [[gnu::always_inline]] auto length () const noexcept -> size_t { diff --git a/src/native-clr/include/runtime-base/timing-internal.hh b/src/native-clr/include/runtime-base/timing-internal.hh new file mode 100644 index 00000000000..d9c29ca53a9 --- /dev/null +++ b/src/native-clr/include/runtime-base/timing-internal.hh @@ -0,0 +1,466 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "startup-aware-lock.hh" +#include "strings.hh" +#include "util.hh" +#include "../constants.hh" +#include "monodroid-state.hh" + +namespace xamarin::android { + // bionic should use `time_t` in the timespec struct, but it uses `long` instead + using time_type = long; + + // Events should never change their assigned values and no values should be reused. + // Values are used by the test runner to determine what measurement was taken. + // + // At the same time, the list should be kept sorted alphabetically for easier reading - + // values therefore might be out of order, but always unique. + enum class TimingEventKind + { + AssemblyDecompression = 0, + AssemblyLoad = 1, + AssemblyPreload = 2, + DebugStart = 3, + Init = 4, + JavaToManaged = 5, + ManagedToJava = 6, + MonoRuntimeInit = 7, + NativeToManagedTransition = 8, + RuntimeConfigBlob = 9, + RuntimeRegister = 10, + TotalRuntimeInit = 11, + Unspecified = 12, + }; + + struct TimingEventPoint + { + time_t sec; + uint64_t ns; + }; + + struct TimingInterval + { + time_t sec; + uint32_t ms; + uint32_t ns; + }; + + struct TimingEvent + { + bool before_managed; + TimingEventPoint start; + TimingEventPoint end; + TimingEventKind kind; + std::unique_ptr more_info; + }; + + template + concept TimingPointType = requires (T a) { + { a.sec } -> std::same_as; + { a.ns } -> std::same_as; + }; + + template + concept TimingIntervalType = requires (T a) { + { a.sec } -> std::same_as; + { a.ms } -> std::same_as; + { a.ns } -> std::same_as; + }; + + class FastTiming final + { + // Number of TimingEvent entries in the event vector allocated at the + // time of class instantiation. It's an arbitrary value, but it should + // be large enough to not require any dynamic reallocation of memory at + // the run time. + static constexpr size_t INITIAL_EVENT_VECTOR_SIZE = 4096uz; + static constexpr uint32_t ns_in_millisecond = 1000000u; + static constexpr uint32_t ms_in_second = 1000u; + static constexpr uint32_t ns_in_second = ms_in_second * ns_in_millisecond; + + protected: + FastTiming () noexcept + { + events.reserve (INITIAL_EVENT_VECTOR_SIZE); + } + + public: + [[gnu::always_inline]] + static auto enabled () noexcept -> bool + { + return is_enabled; + } + + [[gnu::always_inline]] + static auto is_bare_mode () noexcept -> bool + { + return + (Logger::log_timing_categories() & LogTimingCategories::Bare) == LogTimingCategories::Bare || + (Logger::log_timing_categories() & LogTimingCategories::FastBare) == LogTimingCategories::FastBare; + } + + [[gnu::always_inline]] + static void initialize (bool log_immediately) noexcept + { + if (!Util::should_log (LOG_TIMING)) [[likely]] { + return; + } + + mark (init_time.start); + really_initialize (log_immediately); + mark (init_time.end); + + init_time.before_managed = true; + init_time.kind = TimingEventKind::Init; + + if (!immediate_logging) { + return; + } + + log (init_time, false /* skip_log_if_more_info_missing */); + } + + // std::vector isn't used in a conventional manner here. We treat it as if it was a standard array and we + // don't take advantage of any emplacement functionality, merely using vector's ability to resize itself when + // needed. The reason for this is speed - we can atomically increase index into the array and relatively + // quickly check whether it's within the boundaries. We can then safely use thus indexed element without + // worrying about concurrency. Emplacing a new element in the vector would require holding the mutex, something + // that's fairly costly and has unpredictable effect on time spent acquiring and holding the lock (the OS can + // preempt us at this point) + [[gnu::always_inline]] + auto start_event (TimingEventKind kind = TimingEventKind::Unspecified) noexcept -> size_t + { + size_t index = next_event_index.fetch_add (1); + + if (index >= events.capacity ()) [[unlikely]] { + StartupAwareLock lock (event_vector_realloc_mutex); + if (index >= events.size ()) { // don't increase unnecessarily, if another thread has already done that + // Double the vector size. We should, in theory, check for integer overflow here, but it's more + // likely we'll run out of memory way, way, way before that happens + size_t old_size = events.capacity (); + events.reserve (old_size << 1); + log_warn (LOG_TIMING, "Reallocated timing event buffer from {} to {}", old_size, events.size ()); + } + } + + TimingEvent &ev = events[index]; + mark (ev.start); + ev.kind = kind; + ev.before_managed = MonodroidState::is_startup_in_progress (); + ev.more_info = nullptr; + + return index; + } + + [[gnu::always_inline]] + void end_event (size_t event_index, bool uses_more_info = false) noexcept + { + if (!is_valid_event_index (event_index, __PRETTY_FUNCTION__)) [[unlikely]] { + return; + } + + mark (events[event_index].end); + log (events[event_index], uses_more_info /* skip_log_if_more_info_missing */); + } + + template + [[gnu::always_inline]] + void add_more_info (size_t event_index, string_base const& str) noexcept + { + if (!is_valid_event_index (event_index, __PRETTY_FUNCTION__)) [[unlikely]] { + return; + } + + events[event_index].more_info = std::make_unique (str.get (), str.length ()); + log (events[event_index], false /* skip_log_if_more_info_missing */); + } + + [[gnu::always_inline]] + void add_more_info (size_t event_index, const char* str) noexcept + { + if (!is_valid_event_index (event_index, __PRETTY_FUNCTION__)) [[unlikely]] { + return; + } + + events[event_index].more_info = std::make_unique (str); + log (events[event_index], false /* skip_log_if_more_info_missing */); + } + + [[gnu::always_inline]] + static void get_time (time_t &seconds_out, uint64_t& ns_out) noexcept + { + int ret; + timespec tv_ctm; + + ret = clock_gettime (CLOCK_MONOTONIC, &tv_ctm); + ns_out = ret == 0 ? static_cast(tv_ctm.tv_nsec) : 0; + seconds_out = ret == 0 ? tv_ctm.tv_sec : 0; + } + + template [[gnu::always_inline]] + static void calculate_interval (P const& start, P const& end, I &result) noexcept + { + uint64_t nsec; + if (end.ns < start.ns) { + result.sec = end.sec - start.sec - 1; + if (result.sec < 0) { + result.sec = 0; + } + nsec = 1000000000ULL + end.ns - start.ns; + } else { + result.sec = end.sec - start.sec; + nsec = end.ns - start.ns; + } + + result.ms = static_cast(nsec / ns_in_millisecond); + if (result.ms >= ms_in_second) { + result.sec += result.ms / ms_in_second; + result.ms = result.ms % ms_in_second; + } + + result.ns = static_cast(nsec % ns_in_millisecond); + } + + template [[gnu::always_inline]] + static void calculate_interval (P const& start, P const& end, I &result, uint64_t& total_ns) noexcept + { + calculate_interval (start, end, result); + total_ns = + (static_cast(result.sec) * static_cast(ns_in_second)) + + (static_cast(result.ms) * static_cast(ns_in_millisecond)) + + static_cast(result.ns); + } + + void dump () noexcept; + + private: + static void really_initialize (bool log_immediately) noexcept; + static void* timing_signal_thread (void *arg) noexcept; + + [[gnu::always_inline]] + static void mark (TimingEventPoint &point) noexcept + { + get_time (point.sec, point.ns); + } + + [[gnu::always_inline]] + auto is_valid_event_index (size_t index, const char *method_name) noexcept -> bool + { + if (index >= events.capacity ()) [[unlikely]] { + log_warn (LOG_TIMING, "Invalid event index passed to method '{}'", method_name); + return false; + } + + return true; + } + + template [[gnu::always_inline]] + static void append_event_kind_description (TimingEventKind kind, dynamic_local_string& message) noexcept + { + switch (kind) { + case TimingEventKind::AssemblyDecompression: { + constexpr char desc[] = "LZ4 decompression time for "; + message.append (desc); + return; + } + + case TimingEventKind::AssemblyLoad: { + constexpr char desc[] = "Assembly load"; + message.append (desc); + return; + } + + case TimingEventKind::AssemblyPreload: { + constexpr char desc[] = "Finished preloading, number of loaded assemblies: "; + message.append (desc); + return; + } + + case TimingEventKind::DebugStart: { + constexpr char desc[] = "Debug::start_debugging_and_profiling: end"; + message.append (desc); + return; + } + + case TimingEventKind::Init: { + constexpr char desc[] = "XATiming: init time"; + message.append (desc); + return; + } + + case TimingEventKind::JavaToManaged: { + constexpr char desc[] = "Typemap.java_to_managed: end, total time"; + message.append (desc); + return; + } + + case TimingEventKind::ManagedToJava: { + constexpr char desc[] = "Typemap.managed_to_java: end, total time"; + message.append (desc); + return; + } + + case TimingEventKind::MonoRuntimeInit: { + constexpr char desc[] = "Runtime.init: Mono runtime init"; + message.append (desc); + return; + } + + case TimingEventKind::NativeToManagedTransition: { + constexpr char desc[] = "Runtime.init: end native-to-managed transition"; + message.append (desc); + return; + } + + case TimingEventKind::RuntimeConfigBlob: { + constexpr char desc[] = "Register runtimeconfig binary blob"; + message.append (desc); + return; + } + + case TimingEventKind::RuntimeRegister: { + constexpr char desc[] = "Runtime.register: end time. Registered type: "; + message.append (desc); + return; + } + + case TimingEventKind::TotalRuntimeInit: { + constexpr char desc[] = "Runtime.init: end, total time"; + message.append (desc); + return; + } + + default: { + constexpr char desc[] = "Unknown timing event"; + message.append (desc); + return; + } + } + } + + // + // Message format is as follows: [STAGE/EVENT] ; elapsed s:ms::ns + // + // STAGE is one of: + // 0 - native init (before managed code runs) + // 1 - managed code enabled + // 2 - events summary (see the `dump()` function) + // + // EVENT is one of: + // for stages 0 and 1, it's the value of the TimingEventKind member + // for stage 2 see the `dump()` function + // + // The [STAGE/EVENT] format is meant to help the test runner application, so that it can parse logcat without + // having to be kept in sync with the actual wording used for the event message. + // + template [[gnu::always_inline]] + static void format_and_log (TimingEvent const& event, TimingInterval const& interval, dynamic_local_string& message, bool indent = false) noexcept + { + constexpr char INDENT[] = " "; + constexpr char NATIVE_INIT_TAG[] = "[0/"; + constexpr char MANAGED_TAG[] = "[1/"; + + message.clear (); + if (indent) { + message.append (INDENT); + } + + if (event.before_managed) { + message.append (NATIVE_INIT_TAG); + } else { + message.append (MANAGED_TAG); + } + + message.append (static_cast(event.kind)); + message.append ("] "); + + append_event_kind_description (event.kind, message); + if (event.more_info && !event.more_info->empty ()) { + message.append (event.more_info->c_str (), event.more_info->length ()); + } + + constexpr char COLON[] = ":"; + constexpr char TWO_COLONS[] = "::"; + + message.append ("; elapsed: "); + message.append (static_cast(interval.sec)); + message.append (COLON); + message.append (interval.ms); + message.append (TWO_COLONS); + message.append (interval.ns); + + log_write (LOG_TIMING, LogLevel::Info, message.get ()); + } + + template [[gnu::always_inline]] + static void format_and_log (TimingEvent const& event, dynamic_local_string& message, uint64_t& total_ns, bool indent = false) noexcept + { + TimingInterval interval; + calculate_interval (event.start, event.end, interval, total_ns); + format_and_log (event, interval, message, indent); + } + + [[gnu::always_inline]] + static void format_and_log (TimingEvent const& event) noexcept + { + TimingInterval interval; + calculate_interval (event.start, event.end, interval); + + // `message` isn't used here, it is passed to `format_and_log` so that the `dump()` function can + // be slightly more efficient when dumping the event buffer. + dynamic_local_string message; + format_and_log (event, interval, message); + } + + [[gnu::always_inline]] + static void log (TimingEvent const& event, bool skip_log_if_more_info_missing) noexcept + { + if (!immediate_logging) { + return; + } + + if (skip_log_if_more_info_missing && (!event.more_info || event.more_info->empty ())) { + return; + } + + format_and_log (event); + } + + [[gnu::always_inline]] + static void ns_to_time (uint64_t total_ns, uint32_t &sec, uint32_t &ms, uint32_t &ns) noexcept + { + sec = static_cast(total_ns / ns_in_second); + if (sec > 0) { + total_ns = total_ns % 1000000000ULL; + } + + ms = static_cast(total_ns / ns_in_millisecond); + if (ms >= 1000) { + sec += ms / 1000; + ms = ms % 1000; + } + + ns = static_cast(total_ns % ns_in_millisecond); + } + + private: + std::atomic_size_t next_event_index = 0uz; + std::mutex event_vector_realloc_mutex; + std::vector events; + + static inline TimingEvent init_time{}; + static inline bool is_enabled = false; + static inline bool immediate_logging = false; + }; + + extern FastTiming *internal_timing; +} diff --git a/src/native-clr/include/runtime-base/timing.hh b/src/native-clr/include/runtime-base/timing.hh new file mode 100644 index 00000000000..9baf105c4b1 --- /dev/null +++ b/src/native-clr/include/runtime-base/timing.hh @@ -0,0 +1,149 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "logger.hh" + +namespace xamarin::android +{ + struct timing_point + { + time_t sec = 0; + uint64_t ns = 0; + + void mark (); + + void reset () + { + sec = 0; + ns = 0; + } + }; + + struct timing_period + { + timing_point start; + timing_point end; + + void mark_start () + { + start.mark (); + } + + void mark_end () + { + end.mark (); + } + + void reset () + { + start.reset (); + end.reset (); + } + }; + + struct timing_diff + { + static constexpr uint32_t ms_in_nsec = 1000000ULL; + + time_t sec; + uint32_t ms; + uint32_t ns; + + timing_diff (const timing_period &period); + }; + + struct managed_timing_sequence + { + timing_period period; + bool in_use; + bool dynamic; + }; + + // This class is intended to be used by the managed code. It can be used by the native code as + // well, but the overhead it has (out of necessity) might not be desirable in native code. + class Timing + { + static inline constexpr std::string_view MESSAGE_FORMAT { "{}; elapsed: {}:{}::{}" }; + + public: + static constexpr size_t DEFAULT_POOL_SIZE = 16uz; + + public: + explicit Timing (size_t initial_pool_size = DEFAULT_POOL_SIZE) noexcept + : sequence_pool_size (initial_pool_size) + { + sequence_pool = new managed_timing_sequence [initial_pool_size] (); + } + + ~Timing () noexcept + { + delete[] sequence_pool; + } + + static void info (timing_period const &period, const char *message) noexcept + { + timing_diff diff (period); + + log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); + } + + static void warn (timing_period const &period, const char *message) noexcept + { + timing_diff diff (period); + + log_warn (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); + } + + managed_timing_sequence* get_available_sequence () noexcept + { + std::lock_guard lock (sequence_lock); + + managed_timing_sequence *ret; + for (size_t i = 0uz; i < sequence_pool_size; i++) { + if (sequence_pool[i].in_use) { + continue; + } + + ret = &sequence_pool[i]; + ret->in_use = true; + ret->dynamic = false; + + return ret; + } + + ret = new managed_timing_sequence (); + ret->dynamic = true; + + return ret; + } + + void release_sequence (managed_timing_sequence *sequence) + { + if (sequence == nullptr) + return; + + std::lock_guard lock (sequence_lock); + if (sequence->dynamic) { + sequence->period.reset (); + delete sequence; + return; + } + + sequence->in_use = false; + } + + private: + managed_timing_sequence *sequence_pool; + size_t sequence_pool_size; + std::mutex sequence_lock; + }; +} diff --git a/src/native-clr/include/runtime-base/util.hh b/src/native-clr/include/runtime-base/util.hh new file mode 100644 index 00000000000..d469871b6eb --- /dev/null +++ b/src/native-clr/include/runtime-base/util.hh @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +#include "logger.hh" + +namespace xamarin::android { + class Util + { + public: + static void create_public_directory (std::string_view const& dir); + static auto monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE*; + static void set_world_accessable (std::string_view const& path); + + static auto should_log (LogCategories category) noexcept -> bool + { + return (log_categories & category) != 0; + } + }; +} diff --git a/src/native-clr/runtime-base/CMakeLists.txt b/src/native-clr/runtime-base/CMakeLists.txt index 6f2c07bb299..462a62e36dc 100644 --- a/src/native-clr/runtime-base/CMakeLists.txt +++ b/src/native-clr/runtime-base/CMakeLists.txt @@ -3,6 +3,10 @@ set(LIB_ALIAS xa::runtime-base-clr) set(XA_RUNTIME_BASE_SOURCES android-system.cc + logger.cc + timing.cc + timing-internal.cc + util.cc ) add_clang_check_sources("${XA_RUNTIME_BASE_SOURCES}") diff --git a/src/native-clr/runtime-base/logger.cc b/src/native-clr/runtime-base/logger.cc new file mode 100644 index 00000000000..c0d06769988 --- /dev/null +++ b/src/native-clr/runtime-base/logger.cc @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace xamarin::android; +using std::operator""sv; + +namespace { + FILE* + open_file (LogCategories category, std::string const& custom_path, std::string_view const& override_dir, std::string_view const& filename) + { + bool ignore_path = false; + if (!custom_path.empty () && access (custom_path.c_str (), W_OK) < 0) { + log_warn (category, + "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", + custom_path, + strerror (errno), + override_dir, + filename + ); + ignore_path = true; + } + + std::string p{}; + if (custom_path.empty () || ignore_path) { + Util::create_public_directory (override_dir); + p.assign (override_dir); + p.append ("/"); + p.append (filename); + } + + std::string const& path = p.empty () ? custom_path : p; + unlink (path.c_str ()); + + FILE *f = Util::monodroid_fopen (path, "a"sv); + + if (f) { + Util::set_world_accessable (path); + } else { + log_warn (category, "Could not open path '{}' for logging: {}", path, strerror (errno)); + } + + return f; + } + + std::string gref_file{}; + std::string lref_file{}; + bool light_gref = false; + bool light_lref = false; +} + +void +Logger::init_reference_logging (std::string_view const& override_dir) noexcept +{ + if ((log_categories & LOG_GREF) != 0 && !light_gref) { + _gref_log = open_file (LOG_GREF, gref_file, override_dir, "grefs.txt"sv); + } + + if ((log_categories & LOG_LREF) != 0 && !light_lref) { + // if both lref & gref have files specified, and they're the same path, reuse the FILE*. + if (!lref_file.empty () && strcmp (lref_file.c_str (), !gref_file.empty () ? gref_file.c_str () : "") == 0) { + _lref_log = _gref_log; + } else { + _lref_log = open_file (LOG_LREF, lref_file, override_dir, "lrefs.txt"sv); + } + } +} + +[[gnu::always_inline]] bool +Logger::set_category (std::string_view const& name, string_segment& arg, unsigned int entry, bool arg_starts_with_name) noexcept +{ + if ((log_categories & entry) == entry) { + return false; + } + + if (arg_starts_with_name ? arg.starts_with (name) : arg.equal (name)) { + log_categories |= entry; + return true; + } + + return false; +} + +void +Logger::init_logging_categories () noexcept +{ + _log_timing_categories = LogTimingCategories::Default; + + dynamic_local_string value; + if (AndroidSystem::monodroid_get_system_property (Constants::DEBUG_MONO_LOG_PROPERTY, value) == 0) { + return; + } + + string_segment param; + while (value.next_token (',', param)) { + constexpr std::string_view CAT_ALL { "all" }; + + if (param.equal (CAT_ALL)) { + log_categories = 0xFFFFFFFF; + break; + } + + if (set_category ("assembly", param, LOG_ASSEMBLY)) { + continue; + } + + if (set_category ("default", param, LOG_DEFAULT)) { + continue; + } + + if (set_category ("debugger", param, LOG_DEBUGGER)) { + continue; + } + + if (set_category ("gc", param, LOG_GC)) { + continue; + } + + if (set_category ("gref", param, LOG_GREF)) { + continue; + } + + if (set_category ("lref", param, LOG_LREF)) { + continue; + } + + if (set_category ("timing", param, LOG_TIMING)) { + continue; + } + + if (set_category ("network", param, LOG_NET)) { + continue; + } + + if (set_category ("netlink", param, LOG_NETLINK)) { + continue; + } + + auto get_log_file_name = [](std::string_view const& file_kind, string_segment const& segment, size_t offset) -> const char* { + auto file_name = segment.at (offset); + + if (!file_name.has_value ()) { + log_warn (LOG_DEFAULT, "Unable to set path to {} log file: {}", file_kind, to_string (file_name.error ())); + return nullptr; + } + + return file_name.value (); + }; + + constexpr std::string_view CAT_GREF_EQUALS { "gref=" }; + if (set_category (CAT_GREF_EQUALS, param, LOG_GREF, true /* arg_starts_with_name */)) { + gref_file = get_log_file_name ("gref"sv, param, CAT_GREF_EQUALS.length ()); + continue; + } + + if (set_category ("gref-", param, LOG_GREF)) { + light_gref = true; + continue; + } + + if (set_category ("gref+", param, LOG_GREF)) { + _gref_to_logcat = true; + continue; + } + + constexpr std::string_view CAT_LREF_EQUALS { "lref=" }; + if (set_category (CAT_LREF_EQUALS, param, LOG_LREF, true /* arg_starts_with_name */)) { + lref_file = get_log_file_name ("lref"sv, param, CAT_LREF_EQUALS.length ()); + continue; + } + + if (set_category ("lref-", param, LOG_LREF)) { + light_lref = true; + continue; + } + + if (set_category ("lref+", param, LOG_LREF)) { + _lref_to_logcat = true; + continue; + } + + if (param.starts_with ("timing=fast-bare")) { + log_categories |= LOG_TIMING; + _log_timing_categories |= LogTimingCategories::FastBare; + continue; + } + + if (param.starts_with ("timing=bare")) { + log_categories |= LOG_TIMING; + _log_timing_categories |= LogTimingCategories::Bare; + continue; + } + } + + if ((log_categories & LOG_GC) != 0) { + _gc_spew_enabled = true; + } +} diff --git a/src/native-clr/runtime-base/timing-internal.cc b/src/native-clr/runtime-base/timing-internal.cc new file mode 100644 index 00000000000..fab5e4ed160 --- /dev/null +++ b/src/native-clr/runtime-base/timing-internal.cc @@ -0,0 +1,83 @@ +#include +#include + +using namespace xamarin::android; + +namespace xamarin::android { + FastTiming *internal_timing = nullptr; +} + +void +FastTiming::really_initialize (bool log_immediately) noexcept +{ + internal_timing = new FastTiming (); + is_enabled = true; + immediate_logging = log_immediately; + + if (immediate_logging) { + return; + } + + log_write (LOG_TIMING, LogLevel::Info, "[2/1] To get timing results, send the mono.android.app.DUMP_TIMING_DATA intent to the application"); +} + +void +FastTiming::dump () noexcept +{ + if (immediate_logging) { + return; + } + + StartupAwareLock lock { event_vector_realloc_mutex }; + size_t entries = next_event_index.load (); + + log_write (LOG_TIMING, LogLevel::Info, "[2/2] Performance measurement results"); + if (entries == 0) { + log_write (LOG_TIMING, LogLevel::Info, "[2/3] No events logged"); + return; + } + + dynamic_local_string message; + + // Values are in nanoseconds + uint64_t total_assembly_load_time = 0u; + uint64_t total_java_to_managed_time = 0u; + uint64_t total_managed_to_java_time = 0u; + uint64_t total_ns; + + format_and_log (init_time, message, total_ns, true /* indent */); + for (size_t i = 0uz; i < entries; i++) { + TimingEvent const& event = events[i]; + format_and_log (event, message, total_ns, true /* indent */); + + switch (event.kind) { + case TimingEventKind::AssemblyLoad: + total_assembly_load_time += total_ns; + break; + + case TimingEventKind::JavaToManaged: + total_java_to_managed_time += total_ns; + break; + + case TimingEventKind::ManagedToJava: + total_managed_to_java_time += total_ns; + break; + + default: + // Ignore other kinds + break; + } + } + + uint32_t sec, ms, ns; + log_write (LOG_TIMING, LogLevel::Info, "[2/4] Accumulated performance results"); + + ns_to_time (total_assembly_load_time, sec, ms, ns); + log_info_nocheck (LOG_TIMING, " [2/5] Assembly load: {}:{}::{}", sec, ms, ns); + + ns_to_time (total_java_to_managed_time, sec, ms, ns); + log_info_nocheck (LOG_TIMING, " [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns); + + ns_to_time (total_managed_to_java_time, sec, ms, ns); + log_info_nocheck (LOG_TIMING, " [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns); +} diff --git a/src/native-clr/runtime-base/timing.cc b/src/native-clr/runtime-base/timing.cc new file mode 100644 index 00000000000..930139e06e4 --- /dev/null +++ b/src/native-clr/runtime-base/timing.cc @@ -0,0 +1,14 @@ +#include +#include + +using namespace xamarin::android; + +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-clr/runtime-base/util.cc b/src/native-clr/runtime-base/util.cc new file mode 100644 index 00000000000..1fb943b90cd --- /dev/null +++ b/src/native-clr/runtime-base/util.cc @@ -0,0 +1,45 @@ +#include +#include + +#include + +#include +#include + +using namespace xamarin::android; + +void Util::create_public_directory (std::string_view const& dir) +{ + mode_t m = umask (0); + int ret = mkdir (dir.data (), 0777); + if (ret < 0) { + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); + } + umask (m); +} + +auto Util::monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE* +{ + /* On Unix, both path and system calls are all assumed + * to be UTF-8 compliant. + */ + FILE *ret = fopen (filename.data (), mode.data ()); + if (ret == nullptr) { + log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); + return nullptr; + } + + return ret; +} + +void Util::set_world_accessable (std::string_view const& path) +{ + int r; + do { + r = chmod (path.data (), 0664); + } while (r == -1 && errno == EINTR); + + if (r == -1) { + log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); + } +} From 16cf5a1f1398df70d6aeb026490a656e4b13ffa1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 4 Dec 2024 23:10:03 +0100 Subject: [PATCH 028/143] Beginnings of initialization code --- src/native-clr/host/host-jni.cc | 13 ++ src/native-clr/host/host.cc | 25 ++- src/native-clr/include/constants.hh | 8 + src/native-clr/include/host/host.hh | 2 +- .../include/runtime-base/android-system.hh | 8 + .../include/runtime-base/jni-wrappers.hh | 209 ++++++++++++++++++ .../include/runtime-base/strings.hh | 3 +- src/native-clr/include/runtime-base/util.hh | 95 ++++++++ src/native-clr/include/shared/cpp-util.hh | 63 +++++- src/native-clr/runtime-base/android-system.cc | 23 ++ src/native-clr/runtime-base/util.cc | 41 +++- src/native/mono/shared/cpp-util.hh | 2 +- 12 files changed, 481 insertions(+), 11 deletions(-) create mode 100644 src/native-clr/include/runtime-base/jni-wrappers.hh diff --git a/src/native-clr/host/host-jni.cc b/src/native-clr/host/host-jni.cc index 43775ad0918..349bd178221 100644 --- a/src/native-clr/host/host-jni.cc +++ b/src/native-clr/host/host-jni.cc @@ -33,6 +33,19 @@ Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) { + Host::Java_mono_android_Runtime_initInternal ( + env, + klass, + lang, + runtimeApksJava, + runtimeNativeLibDir, + appDirs, + localDateTimeOffset, + loader, + assembliesJava, + isEmulator, + haveSplitApks + ); } JNIEXPORT void diff --git a/src/native-clr/host/host.cc b/src/native-clr/host/host.cc index 5d3e5830c62..9164449d064 100644 --- a/src/native-clr/host/host.cc +++ b/src/native-clr/host/host.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -17,10 +18,26 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, js FastTiming::initialize ((Logger::log_timing_categories() & LogTimingCategories::FastBare) != LogTimingCategories::FastBare); size_t total_time_index; - if (FastTiming::enabled ()) [[unlikely]] { - _timing = std::make_unique (); - total_time_index = internal_timing->start_event (TimingEventKind::TotalRuntimeInit); - } + if (FastTiming::enabled ()) [[unlikely]] { + _timing = std::make_unique (); + total_time_index = internal_timing->start_event (TimingEventKind::TotalRuntimeInit); + } + + jstring_array_wrapper applicationDirs (env, appDirs); + + jstring_wrapper jstr (env, lang); + Util::set_environment_variable ("LANG", jstr); + + jstring_wrapper &home = applicationDirs[Constants::APP_DIRS_FILES_DIR_INDEX]; + Util::set_environment_variable_for_directory ("TMPDIR", applicationDirs[Constants::APP_DIRS_CACHE_DIR_INDEX]); + Util::set_environment_variable_for_directory ("HOME", home); + + AndroidSystem::detect_embedded_dso_mode (applicationDirs); + AndroidSystem::set_running_in_emulator (isEmulator); + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing->end_event (total_time_index); + } } auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint diff --git a/src/native-clr/include/constants.hh b/src/native-clr/include/constants.hh index d18ba60e0ed..e7a5018b06c 100644 --- a/src/native-clr/include/constants.hh +++ b/src/native-clr/include/constants.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -95,5 +96,12 @@ namespace xamarin::android { // Documented in NDK's comments static constexpr size_t MAX_LOGCAT_MESSAGE_LENGTH = 1023uz; + + // PATH_MAX is always 4096 on Linux, but for our purposes it's most likely too much and since + // we use this value to allocate stack variables mostly, let's downsize it a bit to what the + // _XOPEN_PATH_MAX is set to + static constexpr size_t SENSIBLE_PATH_MAX = 1024uz; + + static constexpr int DEFAULT_DIRECTORY_MODE = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; }; } diff --git a/src/native-clr/include/host/host.hh b/src/native-clr/include/host/host.hh index 577dc77f9e3..d7c613da750 100644 --- a/src/native-clr/include/host/host.hh +++ b/src/native-clr/include/host/host.hh @@ -1,6 +1,6 @@ #pragma once -#include +#include #include diff --git a/src/native-clr/include/runtime-base/android-system.hh b/src/native-clr/include/runtime-base/android-system.hh index ad9975f9fc6..974cdecb97d 100644 --- a/src/native-clr/include/runtime-base/android-system.hh +++ b/src/native-clr/include/runtime-base/android-system.hh @@ -4,6 +4,7 @@ #include "../constants.hh" #include "../shared/log_types.hh" +#include "jni-wrappers.hh" #include "strings.hh" namespace xamarin::android { @@ -26,14 +27,21 @@ namespace xamarin::android { } static auto monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int; + static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; private: static auto lookup_system_property (std::string_view const &name, size_t &value_len) noexcept -> const char*; static auto monodroid__system_property_get (std::string_view const&, char *sp_value, size_t sp_value_len) noexcept -> int; static auto get_max_gref_count_from_system () noexcept -> long; + static void set_embedded_dso_mode_enabled (bool yesno) noexcept + { + embedded_dso_mode_enabled = yesno; + } + private: static inline long max_gref_count = 0; static inline bool running_in_emulator = false; + static inline bool embedded_dso_mode_enabled = false; }; } diff --git a/src/native-clr/include/runtime-base/jni-wrappers.hh b/src/native-clr/include/runtime-base/jni-wrappers.hh new file mode 100644 index 00000000000..679aed3df59 --- /dev/null +++ b/src/native-clr/include/runtime-base/jni-wrappers.hh @@ -0,0 +1,209 @@ +#pragma once + +#include + +#include + +#include + +namespace xamarin::android +{ + class jstring_array_wrapper; + + class jstring_wrapper + { + public: + explicit jstring_wrapper (JNIEnv *_env) noexcept + : env (_env), + jstr (nullptr) + { + abort_if_invalid_pointer_argument (_env, "_env"); + } + + explicit jstring_wrapper (JNIEnv *_env, const jobject jo) noexcept + : env (_env), + jstr (reinterpret_cast (jo)) + { + abort_if_invalid_pointer_argument (_env, "_env"); + } + + explicit jstring_wrapper (JNIEnv *_env, const jstring js) noexcept + : env (_env), + jstr (js) + { + abort_if_invalid_pointer_argument (_env, "_env"); + } + + jstring_wrapper (const jstring_wrapper&) = delete; + + ~jstring_wrapper () noexcept + { + release (); + } + + jstring_wrapper& operator=(const jstring_wrapper&) = delete; + + bool hasValue () noexcept + { + return jstr != nullptr; + } + + private: + [[gnu::always_inline]] + void ensure_cstr () noexcept + { + if (cstr != nullptr || env == nullptr) { + return; + } + + cstr = env->GetStringUTFChars (jstr, nullptr); + } + + public: + const char* get_cstr () noexcept + { + if (jstr == nullptr) { + return nullptr; + } + + ensure_cstr (); + return cstr; + } + + [[gnu::always_inline]] + const std::string_view get_string_view () noexcept + { + if (jstr == nullptr) { + return {}; + } + + ensure_cstr (); + return {cstr}; + } + + jstring_wrapper& operator= (const jobject new_jo) noexcept + { + assign (reinterpret_cast (new_jo)); + return *this; + } + + jstring_wrapper& operator= (const jstring new_js) noexcept + { + assign (new_js); + return *this; + } + + protected: + void release () noexcept + { + if (jstr == nullptr || cstr == nullptr || env == nullptr) { + return; + } + env->ReleaseStringUTFChars (jstr, cstr); + jobjectRefType type = env->GetObjectRefType (jstr); + switch (type) { + case JNILocalRefType: + env->DeleteLocalRef (jstr); + break; + + case JNIGlobalRefType: + env->DeleteGlobalRef (jstr); + break; + + case JNIWeakGlobalRefType: + env->DeleteWeakGlobalRef (jstr); + break; + + case JNIInvalidRefType: // To hush compiler warning + break; + } + + jstr = nullptr; + cstr = nullptr; + } + + void assign (const jstring new_js) noexcept + { + release (); + if (new_js == nullptr) { + return; + } + + jstr = new_js; + cstr = nullptr; + } + + friend class jstring_array_wrapper; + + private: + jstring_wrapper () + : env (nullptr), + jstr (nullptr) + {} + + private: + JNIEnv *env; + jstring jstr; + const char *cstr = nullptr; + }; + + class jstring_array_wrapper + { + public: + explicit jstring_array_wrapper (JNIEnv *_env) noexcept + : jstring_array_wrapper(_env, nullptr) + {} + + explicit jstring_array_wrapper (JNIEnv *_env, jobjectArray _arr) + : env (_env), + arr (_arr) + { + abort_if_invalid_pointer_argument (_env, "_env"); + if (_arr != nullptr) { + len = static_cast(_env->GetArrayLength (_arr)); + if (len > sizeof (static_wrappers) / sizeof (jstring_wrapper)) { + wrappers = new jstring_wrapper [len]; + } else { + wrappers = static_wrappers; + } + } else { + len = 0; + wrappers = nullptr; + } + } + + ~jstring_array_wrapper () noexcept + { + if (wrappers != nullptr && wrappers != static_wrappers) { + delete[] wrappers; + } + } + + size_t get_length () const noexcept + { + return len; + } + + jstring_wrapper& operator[] (size_t index) noexcept + { + if (index >= len) { + return invalid_wrapper; + } + + if (wrappers [index].env == nullptr) { + wrappers [index].env = env; + wrappers [index].jstr = reinterpret_cast (env->GetObjectArrayElement (arr, static_cast(index))); + } + + return wrappers [index]; + } + + private: + JNIEnv *env; + jobjectArray arr; + size_t len; + jstring_wrapper *wrappers; + jstring_wrapper static_wrappers[5]; + jstring_wrapper invalid_wrapper; + }; +} diff --git a/src/native-clr/include/runtime-base/strings.hh b/src/native-clr/include/runtime-base/strings.hh index cfdb56f53b9..aae49968f84 100644 --- a/src/native-clr/include/runtime-base/strings.hh +++ b/src/native-clr/include/runtime-base/strings.hh @@ -534,8 +534,9 @@ namespace xamarin::android { [[gnu::always_inline]] auto append_c (const char *s) noexcept -> string_base& { - if (s == nullptr) + if (s == nullptr) { return *this; + } return append (s, strlen (s)); } diff --git a/src/native-clr/include/runtime-base/util.hh b/src/native-clr/include/runtime-base/util.hh index d469871b6eb..f19feafc3c2 100644 --- a/src/native-clr/include/runtime-base/util.hh +++ b/src/native-clr/include/runtime-base/util.hh @@ -1,14 +1,37 @@ #pragma once +#include #include #include +#include + +#include "../constants.hh" +#include "../shared/helpers.hh" +#include "jni-wrappers.hh" #include "logger.hh" +#include "strings.hh" namespace xamarin::android { + namespace detail { + template + concept PathComponentString = requires { + std::same_as, char*> || + std::same_as, std::string_view> || + std::same_as, std::string>; + }; + + template + concept PathBuffer = requires { + std::derived_from, dynamic_local_storage> || + std::derived_from, static_local_storage>; + }; + } + class Util { public: + static int create_directory (const char *pathname, mode_t mode); static void create_public_directory (std::string_view const& dir); static auto monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE*; static void set_world_accessable (std::string_view const& path); @@ -17,5 +40,77 @@ namespace xamarin::android { { return (log_categories & category) != 0; } + + static auto file_exists (const char *file) noexcept -> bool + { + if (file == nullptr) { + return false; + } + + struct stat s; + if (::stat (file, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG) { + return true; + } + return false; + } + + template + static auto file_exists (dynamic_local_string const& file) noexcept -> bool + { + if (file.empty ()) { + return false; + } + + return file_exists (file.get ()); + } + + static void set_environment_variable (std::string_view const& name, jstring_wrapper& value) noexcept + { + ::setenv (name.data (), value.get_cstr (), 1); + } + + static void set_environment_variable_for_directory (std::string_view const& name, jstring_wrapper& value, bool createDirectory, mode_t mode) noexcept + { + if (createDirectory) { + int rv = create_directory (value.get_cstr (), mode); + if (rv < 0 && errno != EEXIST) { + log_warn (LOG_DEFAULT, "Failed to create directory '{}' for environment variable '{}'. {}", value.get_string_view (), name, strerror (errno)); + } + } + set_environment_variable (name, value); + } + + static void set_environment_variable_for_directory (const char *name, jstring_wrapper &value) noexcept + { + set_environment_variable_for_directory (name, value, true, Constants::DEFAULT_DIRECTORY_MODE); + } + + private: + template TBuffer, detail::PathComponentString ...TPart> + static void path_combine_common (TBuffer& buf, TPart&&... parts) noexcept + { + buf.clear (); + + for (auto const& part : {parts...}) { + if (!buf.empty ()) { + buf.append ("/"sv); + } + + if constexpr (std::same_as, char*>) { + if (part != nullptr) { + buf.append_c (part); + } + } else { + buf.append (part); + } + } + } + + public: + template + static void path_combine (dynamic_local_string& buf, TParts&&... parts) noexcept + { + path_combine_common (buf, std::forward(parts)...); + } }; } diff --git a/src/native-clr/include/shared/cpp-util.hh b/src/native-clr/include/shared/cpp-util.hh index 2121305dd94..396292613bb 100644 --- a/src/native-clr/include/shared/cpp-util.hh +++ b/src/native-clr/include/shared/cpp-util.hh @@ -6,9 +6,12 @@ #include #include #include +#include #include +#include #include #include +#include #include #include @@ -29,6 +32,50 @@ namespace xamarin::android::detail { va_end (ap); return ret == -1 ? "Out of memory" : message; } + + [[gnu::always_inline]] + static inline std::string get_function_name (const char *signature) + { + using std::operator""sv; + + std::string_view sig { signature }; + if (sig.length () == 0) { + return ""; + } + + auto splitSignature = sig | std::views::split ("::"sv) | std::ranges::to> (); + + std::string ret; + if (splitSignature.size () > 1) { + ret.append (splitSignature [splitSignature.size () - 2]); + ret.append ("::"sv); + } + std::string_view func_name { splitSignature[splitSignature.size () - 1] }; + std::string_view::size_type args_pos = func_name.find ('('); + std::string_view::size_type name_start_pos = func_name.find (' '); + + if (name_start_pos == std::string_view::npos) { + name_start_pos = 0; + } else { + name_start_pos++; // point to after the space which separates return type from name + if (name_start_pos >= func_name.length ()) [[unlikely]] { + name_start_pos = 0; + } + } + + if (args_pos == std::string_view::npos) { + ret.append (func_name.substr (name_start_pos)); + } else { + // If there's a snafu with positions, start from 0 + if (name_start_pos >= args_pos || name_start_pos > func_name.length ()) [[unlikely]] { + name_start_pos = 0; + } + + ret.append (func_name.substr (name_start_pos, args_pos - name_start_pos)); + } + + return ret; + } } template F> @@ -62,7 +109,13 @@ abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_loc { abort_unless ( ptr != nullptr, - [&ptr_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", ptr_name); }, + [&ptr_name, &sloc] { + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a valid pointer", + xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), + ptr_name + ); + }, sloc ); } @@ -73,7 +126,13 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l { abort_unless ( arg > 0, - [&arg_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", arg_name); }, + [&arg_name, &sloc] { + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a positive integer", + xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), + arg_name + ); + }, sloc ); } diff --git a/src/native-clr/runtime-base/android-system.cc b/src/native-clr/runtime-base/android-system.cc index dd381f994a8..b2118026a1f 100644 --- a/src/native-clr/runtime-base/android-system.cc +++ b/src/native-clr/runtime-base/android-system.cc @@ -1,11 +1,34 @@ #include +#include #include #include #include #include +#include using namespace xamarin::android; +using std::operator""sv; + +void +AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept +{ + // appDirs[Constants::APP_DIRS_DATA_DIR_INDEX] points to the native library directory + dynamic_local_string libmonodroid_path; + Util::path_combine (libmonodroid_path, appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_string_view (), "libmonodroid.so"sv); + + log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); + if (!Util::file_exists (libmonodroid_path)) { + log_debug (LOG_ASSEMBLY, "{} 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 {}, assuming application/android:extractNativeLibs == true", appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + set_embedded_dso_mode_enabled (false); + } + + Util::path_combine (libmonodroid_path, "first_part"sv, "second_part"sv, "third_part"sv, "file.txt"sv); + log_warn (LOG_DEFAULT, "path_combine test: {}", libmonodroid_path.get ()); +} auto AndroidSystem::lookup_system_property (std::string_view const& name, size_t &value_len) noexcept -> const char* diff --git a/src/native-clr/runtime-base/util.cc b/src/native-clr/runtime-base/util.cc index 1fb943b90cd..6cce7591a6a 100644 --- a/src/native-clr/runtime-base/util.cc +++ b/src/native-clr/runtime-base/util.cc @@ -8,7 +8,43 @@ using namespace xamarin::android; -void Util::create_public_directory (std::string_view const& dir) +int +Util::create_directory (const char *pathname, mode_t mode) +{ + // if (mode <= 0) + // mode = DEFAULT_DIRECTORY_MODE; + + // if (!pathname || *pathname == '\0') { + // errno = EINVAL; + // return -1; + // } + // mode_t oldumask = umask (022); + // std::unique_ptr path {strdup_new (pathname)}; + // int rv, ret = 0; + // for (char *d = path.get (); d != nullptr && *d; ++d) { + // if (*d != '/') + // continue; + // *d = 0; + // if (*path) { + // rv = make_directory (path.get (), mode); + // if (rv == -1 && errno != EEXIST) { + // ret = -1; + // break; + // } + // } + // *d = '/'; + // } + + // if (ret == 0) + // ret = make_directory (pathname, mode); + // umask (oldumask); + + // return ret; + return -1; +} + +void +Util::create_public_directory (std::string_view const& dir) { mode_t m = umask (0); int ret = mkdir (dir.data (), 0777); @@ -18,7 +54,8 @@ void Util::create_public_directory (std::string_view const& dir) umask (m); } -auto Util::monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE* +auto +Util::monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE* { /* On Unix, both path and system calls are all assumed * to be UTF-8 compliant. diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index abbaa95bb79..aa5df834a37 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -129,7 +129,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l arg > 0, [&arg_name, &sloc] { return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a valid pointer", + "%s: parameter '%s' must be a positive integer", xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), arg_name ); From 3227bcb00d92897e00664269c85309e6b2d4013f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 5 Dec 2024 17:34:26 +0100 Subject: [PATCH 029/143] More environment work --- src/native-clr/host/host.cc | 33 +++ src/native-clr/include/constants.hh | 12 ++ src/native-clr/include/host/host.hh | 5 + .../include/runtime-base/android-system.hh | 57 ++++++ src/native-clr/include/runtime-base/util.hh | 7 + src/native-clr/runtime-base/android-system.cc | 192 +++++++++++++++++- .../xamarin-app-stub/application_dso_stub.cc | 1 + 7 files changed, 297 insertions(+), 10 deletions(-) diff --git a/src/native-clr/host/host.cc b/src/native-clr/host/host.cc index 9164449d064..2e8b58f4bc7 100644 --- a/src/native-clr/host/host.cc +++ b/src/native-clr/host/host.cc @@ -8,6 +8,35 @@ using namespace xamarin::android; +void Host::create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept +{ + static_local_string dir (home_len + relative_path.length ()); + Util::path_combine (dir, home.get_string_view (), relative_path); + + log_debug (LOG_DEFAULT, "Creating XDG directory: {}", optional_string (dir.get ())); + int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE); + if (rv < 0 && errno != EEXIST) { + log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", optional_string (dir.get ()), strerror (errno)); + } + + if (!environment_variable_name.empty ()) { + setenv (environment_variable_name.data (), dir.get (), 1); + } +} + +void Host::create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept +{ + size_t home_len = strlen (homeDir.get_cstr ()); + + constexpr auto XDG_DATA_HOME = "XDG_DATA_HOME"sv; + constexpr auto HOME_PATH = ".local/share"sv; + create_xdg_directory (homeDir, home_len, HOME_PATH, XDG_DATA_HOME); + + constexpr auto XDG_CONFIG_HOME = "XDG_CONFIG_HOME"sv; + constexpr auto CONFIG_PATH = ".config"sv; + create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME); +} + void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) @@ -31,9 +60,13 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, js jstring_wrapper &home = applicationDirs[Constants::APP_DIRS_FILES_DIR_INDEX]; Util::set_environment_variable_for_directory ("TMPDIR", applicationDirs[Constants::APP_DIRS_CACHE_DIR_INDEX]); Util::set_environment_variable_for_directory ("HOME", home); + create_xdg_directories_and_environment (home); AndroidSystem::detect_embedded_dso_mode (applicationDirs); AndroidSystem::set_running_in_emulator (isEmulator); + AndroidSystem::set_primary_override_dir (home); + AndroidSystem::create_update_dir (AndroidSystem::get_primary_override_dir ()); + AndroidSystem::setup_environment (); if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (total_time_index); diff --git a/src/native-clr/include/constants.hh b/src/native-clr/include/constants.hh index e7a5018b06c..f024da0a6eb 100644 --- a/src/native-clr/include/constants.hh +++ b/src/native-clr/include/constants.hh @@ -17,6 +17,13 @@ namespace xamarin::android { #endif public: +#if defined(RELEASE) + static constexpr bool IsReleaseBuild = true; + static constexpr bool IsDebugBuild = false; +#else + static constexpr bool IsReleaseBuild = false; + static constexpr bool IsDebugBuild = true; +#endif static constexpr std::string_view MANGLED_ASSEMBLY_NAME_EXT { ".so" }; private: @@ -103,5 +110,10 @@ namespace xamarin::android { static constexpr size_t SENSIBLE_PATH_MAX = 1024uz; static constexpr int DEFAULT_DIRECTORY_MODE = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + +#if defined (DEBUG) + static constexpr std::string_view OVERRIDE_ENVIRONMENT_FILE_NAME { "environment" }; + static constexpr uint32_t OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE = 22; +#endif }; } diff --git a/src/native-clr/include/host/host.hh b/src/native-clr/include/host/host.hh index d7c613da750..347e318e6c8 100644 --- a/src/native-clr/include/host/host.hh +++ b/src/native-clr/include/host/host.hh @@ -4,6 +4,7 @@ #include +#include "../runtime-base/jni-wrappers.hh" #include "../runtime-base/timing.hh" #include "../shared/log_types.hh" @@ -21,6 +22,10 @@ namespace xamarin::android { return _timing.get (); } + private: + static void create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept; + static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept; + private: static inline std::unique_ptr _timing{}; }; diff --git a/src/native-clr/include/runtime-base/android-system.hh b/src/native-clr/include/runtime-base/android-system.hh index 974cdecb97d..cf21b566dca 100644 --- a/src/native-clr/include/runtime-base/android-system.hh +++ b/src/native-clr/include/runtime-base/android-system.hh @@ -1,11 +1,16 @@ #pragma once +#include #include +#include #include "../constants.hh" #include "../shared/log_types.hh" #include "jni-wrappers.hh" #include "strings.hh" +#include "util.hh" + +struct BundledProperty; namespace xamarin::android { class AndroidSystem @@ -26,22 +31,74 @@ namespace xamarin::android { running_in_emulator = yesno; } + static auto get_primary_override_dir () noexcept -> std::string const& + { + return primary_override_dir; + } + + static void set_primary_override_dir (jstring_wrapper& home) noexcept + { + primary_override_dir = determine_primary_override_dir (home); + } + + static void create_update_dir (std::string const& override_dir) noexcept + { + if constexpr (Constants::IsReleaseBuild) { + /* + * Don't create .__override__ on Release builds, because Google requires + * that pre-loaded apps not create world-writable directories. + * + * However, if any logging is enabled (which should _not_ happen with + * pre-loaded apps!), we need the .__override__ directory... + */ + dynamic_local_string value; + if (log_categories == 0 && monodroid_get_system_property (Constants::DEBUG_MONO_PROFILE_PROPERTY, value) == 0) [[likely]] { + return; + } + } + + Util::create_public_directory (override_dir); + log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); + } + static auto monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int; static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; + static void setup_environment () noexcept; private: static auto lookup_system_property (std::string_view const &name, size_t &value_len) noexcept -> const char*; static auto monodroid__system_property_get (std::string_view const&, char *sp_value, size_t sp_value_len) noexcept -> int; static auto get_max_gref_count_from_system () noexcept -> long; +#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 (dynamic_local_string const& path) noexcept; +#endif static void set_embedded_dso_mode_enabled (bool yesno) noexcept { embedded_dso_mode_enabled = yesno; } + static auto determine_primary_override_dir (jstring_wrapper &home) noexcept -> std::string + { + dynamic_local_string name { home.get_cstr () }; + name.append ("/") + .append (Constants::OVERRIDE_DIRECTORY_NAME) + .append ("/") + .append (Constants::android_lib_abi); + + return {name.get (), name.length ()}; + } + private: static inline long max_gref_count = 0; static inline bool running_in_emulator = false; static inline bool embedded_dso_mode_enabled = false; + static inline std::string primary_override_dir; + +#if defined (DEBUG) + static inline std::unordered_map bundled_properties; +#endif }; } diff --git a/src/native-clr/include/runtime-base/util.hh b/src/native-clr/include/runtime-base/util.hh index f19feafc3c2..555b81e8db2 100644 --- a/src/native-clr/include/runtime-base/util.hh +++ b/src/native-clr/include/runtime-base/util.hh @@ -86,6 +86,7 @@ namespace xamarin::android { } private: + // TODO: needs some work to accept mixed params of different accepted types template TBuffer, detail::PathComponentString ...TPart> static void path_combine_common (TBuffer& buf, TPart&&... parts) noexcept { @@ -112,5 +113,11 @@ namespace xamarin::android { { path_combine_common (buf, std::forward(parts)...); } + + template + static void path_combine (static_local_string& buf, TParts&&... parts) noexcept + { + path_combine_common (buf, std::forward(parts)...); + } }; } diff --git a/src/native-clr/runtime-base/android-system.cc b/src/native-clr/runtime-base/android-system.cc index b2118026a1f..7946cc30580 100644 --- a/src/native-clr/runtime-base/android-system.cc +++ b/src/native-clr/runtime-base/android-system.cc @@ -10,6 +10,179 @@ using namespace xamarin::android; using std::operator""sv; +#if defined(DEBUG) +[[gnu::always_inline]] +void +AndroidSystem::add_system_property (const char *name, const char *value) noexcept +{ + if (name == nullptr || *name == '\0') { + log_warn (LOG_DEFAULT, "Attempt to add a bundled system property without a valid name"); + return; + } + + if (value == nullptr) { + value = ""; + } + + bundled_properties[name] = value; +} + +void +AndroidSystem::setup_environment (const char *name, const char *value) noexcept +{ + if (name == nullptr || *name == '\0') { + return; + } + + const char *v = value; + if (v == nullptr) { + v = ""; + } + + if (isupper (name [0]) || name [0] == '_') { + if (setenv (name, v, 1) < 0) { + log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); + } + return; + } + + add_system_property (name, v); +} + +void +AndroidSystem::setup_environment_from_override_file (dynamic_local_string const& path) noexcept +{ + using read_count_type = size_t; + + struct stat sbuf; + if (::stat (path.get (), &sbuf) < 0) { + log_warn (LOG_DEFAULT, "Failed to stat the environment override file {}: {}", path.get (), strerror (errno)); + return; + } + + int fd = open (path.get (), O_RDONLY); + if (fd < 0) { + log_warn (LOG_DEFAULT, "Failed to open the environment override file {}: {}", path.get (), strerror (errno)); + return; + } + + auto file_size = static_cast(sbuf.st_size); + size_t nread = 0uz; + ssize_t r; + auto buf = std::make_unique (file_size); + + do { + auto read_count = static_cast(file_size - nread); + r = read (fd, buf.get () + nread, read_count); + if (r > 0) { + nread += static_cast(r); + } + } while (r < 0 && errno == EINTR); + + if (nread == 0) { + log_warn (LOG_DEFAULT, "Failed to read the environment override file {}: {}", path.get (), strerror (errno)); + return; + } + + // The file format is as follows (no newlines are used, this is just for illustration + // purposes, comments aren't part of the file either): + // + // # 10 ASCII characters formattted as a C++ hexadecimal number terminated with NUL: name + // # width (including the terminating NUL) + // 0x00000000\0 + // + // # 10 ASCII characters formattted as a C++ hexadecimal number terminated with NUL: value + // # width (including the terminating NUL) + // 0x00000000\0 + // + // # Variable name, terminated with NUL and padded to [name width] with NUL characters + // name\0 + // + // # Variable value, terminated with NUL and padded to [value width] with NUL characters + // value\0 + if (nread < Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) { + log_warn (LOG_DEFAULT, "Invalid format of the environment override file {}: malformatted header", path.get ()); + return; + } + + char *endptr; + unsigned long name_width = strtoul (buf.get (), &endptr, 16); + if ((name_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path.get ()); + return; + } + + unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); + if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path.get ()); + return; + } + + uint64_t data_width = name_width + value_width; + if (data_width > file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { + log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path.get ()); + return; + } + + uint64_t data_size = static_cast(file_size); + char *name = buf.get () + Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE; + while (data_size > 0 && data_size >= data_width) { + if (*name == '\0') { + log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path.get (), name - buf.get ()); + return; + } + + log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path.get (), name, name + name_width); + setup_environment (name, name + name_width); + name += data_width; + data_size -= data_width; + } +} +#endif + +void +AndroidSystem::setup_environment () noexcept +{ + if (application_config.environment_variable_count % 2 != 0) { + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count); + return; + } + + const char *var_name; + const char *var_value; + for (size_t i = 0uz; i < application_config.environment_variable_count; i += 2) { + var_name = app_environment_variables [i]; + if (var_name == nullptr || *var_name == '\0') { + continue; + } + + var_value = app_environment_variables [i + 1uz]; + if (var_value == nullptr) { + var_value = ""; + } + + if constexpr (Constants::IsDebugBuild) { + log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); + } + + if (setenv (var_name, var_value, 1) < 0) { + log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); + } + } + +#if defined(DEBUG) + log_debug (LOG_DEFAULT, "Loading environment from the override directory."sv); + + dynamic_local_string env_override_file; + Util::path_combine (env_override_file, std::string_view {primary_override_dir}, Constants::OVERRIDE_ENVIRONMENT_FILE_NAME); + log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); + if (Util::file_exists (env_override_file)) { + log_debug (LOG_DEFAULT, "Loading {}"sv, env_override_file.get ()); + setup_environment_from_override_file (env_override_file); + } +#endif // def DEBUG +} + void AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept { @@ -25,22 +198,21 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep log_debug (LOG_ASSEMBLY, "Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); set_embedded_dso_mode_enabled (false); } - - Util::path_combine (libmonodroid_path, "first_part"sv, "second_part"sv, "third_part"sv, "file.txt"sv); - log_warn (LOG_DEFAULT, "path_combine test: {}", libmonodroid_path.get ()); } auto AndroidSystem::lookup_system_property (std::string_view const& name, size_t &value_len) noexcept -> const char* { value_len = 0; -// #if defined (DEBUG) -// BundledProperty *p = lookup_system_property (name); -// if (p != nullptr) { -// value_len = p->value_len; -// return p->name; -// } -// #endif // DEBUG || !ANDROID +#if defined (DEBUG) + if (!bundled_properties.empty ()) { + auto prop_iter = bundled_properties.find (name.data ()); + if (prop_iter != bundled_properties.end ()) { + value_len = prop_iter->second.length (); + return prop_iter->first.c_str (); + } + } +#endif // DEBUG if (application_config.system_property_count == 0) { return nullptr; diff --git a/src/native-clr/xamarin-app-stub/application_dso_stub.cc b/src/native-clr/xamarin-app-stub/application_dso_stub.cc index e9a8bf35235..2a34ff4c13d 100644 --- a/src/native-clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native-clr/xamarin-app-stub/application_dso_stub.cc @@ -62,6 +62,7 @@ const ApplicationConfig application_config = { .android_package_name = android_package_name, }; +// TODO: migrate to std::string_view for these two const char* const app_environment_variables[] = {}; const char* const app_system_properties[] = {}; From 9456f80189dbc96aae56f95d5a8953b6526a80cd Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 11:04:09 +0100 Subject: [PATCH 030/143] Enable static linking with libc++ * Add a version script which hides all the symbols except for the handful we have to export. * Enable exceptions --- src/native/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index a1cee1367a6..2c52d0e3c56 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -134,7 +134,7 @@ else() set(USES_LIBSTDCPP True) endif() -set(SHARED_LIB_NAME xa::shared) +set(SHARED_LIB_NAME xa::shared-no-abi) # # Needed modules From c8511c4a2893c52324957cf86fcc0ef6f13e34b2 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 11:11:57 +0100 Subject: [PATCH 031/143] Remove C++ ABI compatibility sources --- src/native/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 2c52d0e3c56..a1cee1367a6 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -134,7 +134,7 @@ else() set(USES_LIBSTDCPP True) endif() -set(SHARED_LIB_NAME xa::shared-no-abi) +set(SHARED_LIB_NAME xa::shared) # # Needed modules From 6adc16ad3a817e94b3ab1680b255ecc2a50e6653 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 16:05:55 +0100 Subject: [PATCH 032/143] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 14 +++--- .../BuildReleaseArm64XFormsDotNet.apkdesc | 43 ++++++++++--------- 2 files changed, 30 insertions(+), 27 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 be94e0bcbf7..574f95f396e 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 @@ -5,7 +5,7 @@ "Size": 3036 }, "classes.dex": { - "Size": 22444 + "Size": 389632 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { "Size": 18296 @@ -14,10 +14,10 @@ "Size": 86352 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 116920 + "Size": 116768 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22408 + "Size": 22416 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24376 @@ -44,7 +44,7 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1501240 + "Size": 903032 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3196512 @@ -62,10 +62,10 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 18264 + "Size": 13016 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { "Size": 3266 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 3111445 + "PackageSize": 2984469 } \ 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 b3173a6f72f..b408abbf0ce 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 @@ -5,7 +5,10 @@ "Size": 6652 }, "classes.dex": { - "Size": 9172764 + "Size": 9448880 + }, + "classes2.dex": { + "Size": 154180 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -32,16 +35,16 @@ "Size": 19544 }, "lib/arm64-v8a/lib_FormsViewGroup.dll.so": { - "Size": 25424 + "Size": 25184 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { "Size": 94736 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 524256 + "Size": 522832 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22408 + "Size": 22416 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21448 @@ -170,31 +173,31 @@ "Size": 22096 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { - "Size": 34960 + "Size": 34760 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.AppCompatResources.dll.so": { - "Size": 24512 + "Size": 24296 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.dll.so": { - "Size": 163240 + "Size": 163072 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CardView.dll.so": { "Size": 24560 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CoordinatorLayout.dll.so": { - "Size": 35912 + "Size": 35680 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Core.dll.so": { - "Size": 151408 + "Size": 151216 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CursorAdapter.dll.so": { "Size": 27168 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.DrawerLayout.dll.so": { - "Size": 33944 + "Size": 33760 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Fragment.dll.so": { - "Size": 72528 + "Size": 72224 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Legacy.Support.Core.UI.dll.so": { "Size": 23896 @@ -212,16 +215,16 @@ "Size": 31592 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.RecyclerView.dll.so": { - "Size": 112248 + "Size": 111896 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SavedState.dll.so": { "Size": 23144 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SwipeRefreshLayout.dll.so": { - "Size": 31952 + "Size": 31672 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager.dll.so": { - "Size": 38048 + "Size": 37752 }, "lib/arm64-v8a/lib_Xamarin.Forms.Core.dll.so": { "Size": 581000 @@ -236,7 +239,7 @@ "Size": 80632 }, "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { - "Size": 84768 + "Size": 84400 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 18832 @@ -245,7 +248,7 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1501240 + "Size": 903032 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3196512 @@ -263,7 +266,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 349440 + "Size": 120016 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -419,7 +422,7 @@ "Size": 1223 }, "META-INF/BNDLTOOL.SF": { - "Size": 98577 + "Size": 98661 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -446,7 +449,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98450 + "Size": 98534 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2486,5 +2489,5 @@ "Size": 812848 } }, - "PackageSize": 10947851 + "PackageSize": 10796357 } \ No newline at end of file From 0be5634d0ea095cb118ff7ddd0b3b79f5d69b1c6 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 31 Oct 2024 19:19:59 +0100 Subject: [PATCH 033/143] Playing around with some ideas --- .../mono/monodroid/embedded-assemblies.hh | 4 +- src/native/mono/monodroid/monodroid-glue.cc | 7 +- src/native/mono/monodroid/osbridge.cc | 6 +- src/native/mono/shared/cpp-util.hh | 96 ++++--------------- 4 files changed, 25 insertions(+), 88 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index bbb91157b10..d0885f77a05 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -173,8 +173,8 @@ namespace xamarin::android::internal { abort_unless ( runtime_config_data_size < std::numeric_limits::max (), [] { - return detail::_format_message ("Runtime config binary blob size exceeds %u bytes", - std::numeric_limits::max ()); + return Util::monodroid_strdup_printf ("Runtime config binary blob size exceeds %u bytes", + std::numeric_limits::max ()); } ); size = static_cast(runtime_config_data_size); diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 135c296a61a..8fb6ce9c0b8 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -917,10 +917,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( registerType != nullptr, [&error] { - return detail::_format_message ( - "INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", - mono_error_get_message (&error) - ); + return Util::monodroid_strdup_printf("INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", mono_error_get_message (&error)); } ); @@ -949,7 +946,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( initialize != nullptr, [&error] { - return detail::_format_message ( + return Util::monodroid_strdup_printf ( "Failed to obtain unmanaged-callers-only pointer to the Android.Runtime.JNIEnvInit.Initialize method. %s", mono_error_get_message (&error) ); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 919506d3fda..c189efd5754 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -880,7 +880,9 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (j > 0) { abort_unless ( sccs [i]->is_alive, - [&i] { return detail::_format_message ("Bridge SCC at index %d must be alive", i); } + [&i] { + return Util::monodroid_strdup_printf ("Bridge SCC at index %d must be alive", i); + } ); } sccs [i]->is_alive = 1; @@ -908,7 +910,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } else { abort_unless ( !sccs [i]->is_alive, - [&i] { return detail::_format_message ("Bridge SCC at index %d must NOT be alive", i); } + [&i] { return Util::monodroid_strdup_printf ("Bridge SCC at index %d must NOT be alive", i); } ); } } diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index aa5df834a37..311c00e9f27 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -19,77 +18,33 @@ #include -namespace xamarin::android::detail { - [[gnu::always_inline, gnu::flatten]] - static inline const char* - _format_message (const char *format, ...) noexcept - { - va_list ap; - va_start (ap, format); + +static inline void +do_abort_unless (const char* fmt, ...) +{ + va_list ap; char *message; int ret = vasprintf (&message, format, ap); - va_end (ap); - return ret == -1 ? "Out of memory" : message; - } - - [[gnu::always_inline]] - static inline std::string get_function_name (const char *signature) - { - using std::operator""sv; - - std::string_view sig { signature }; - if (sig.length () == 0) { - return ""; - } - - auto splitSignature = sig | std::views::split ("::"sv) | std::ranges::to> (); - - std::string ret; - if (splitSignature.size () > 1) { - ret.append (splitSignature [splitSignature.size () - 2]); - ret.append ("::"sv); - } - std::string_view func_name { splitSignature[splitSignature.size () - 1] }; - std::string_view::size_type args_pos = func_name.find ('('); - std::string_view::size_type name_start_pos = func_name.find (' '); - - if (name_start_pos == std::string_view::npos) { - name_start_pos = 0; - } else { - name_start_pos++; // point to after the space which separates return type from name - if (name_start_pos >= func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - } - - if (args_pos == std::string_view::npos) { - ret.append (func_name.substr (name_start_pos)); - } else { - // If there's a snafu with positions, start from 0 - if (name_start_pos >= args_pos || name_start_pos > func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - - ret.append (func_name.substr (name_start_pos, args_pos - name_start_pos)); - } - - return ret; - } + xamarin::android::Helpers::abort_application (n == -1 ? "Unable to allocate memory for abort message" : message); } +// #define abort_unless(_condition_, _fmt_, ...) \ +// if (!(_condition_)) [[unlikely]] { \ +// do_abort_unless ("%s:%d (%s): " _fmt_, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ +// } + template F> [[gnu::always_inline, gnu::flatten]] static inline void abort_unless (bool condition, F&& get_message, std::source_location sloc = std::source_location::current ()) noexcept { - static_assert (std::is_same::type, const char*>::value, "get_message must return 'const char*'"); - if (condition) [[likely]] { return; } +// static_assert (std::is_same, char*>::value, "get_message must return 'char*'"); xamarin::android::Helpers::abort_application (std::invoke (get_message), true /* log_location */, sloc); } @@ -103,39 +58,22 @@ abort_unless (bool condition, const char *message, std::source_location sloc = s xamarin::android::Helpers::abort_application (message, true /* log_location */, sloc); } +// #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_) + template [[gnu::always_inline, gnu::flatten]] static inline void abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless ( - ptr != nullptr, - [&ptr_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a valid pointer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - ptr_name - ); - }, - sloc - ); + abort_unless (ptr != nullptr, "Parameter '%s' must be a valid pointer", sloc); } [[gnu::always_inline, gnu::flatten]] static inline void abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless ( - arg > 0, - [&arg_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a positive integer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - arg_name - ); - }, - sloc - ); + abort_unless (arg > 0, "Parameter '%s' must be a valid pointer", sloc); } // Helper to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any From 9e0d7306be057c3c68fc7425ee33353830399f33 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 4 Nov 2024 20:55:16 +0100 Subject: [PATCH 034/143] More consistent use of std::string_view + remove unused code --- .../mono/monodroid/embedded-assemblies.hh | 15 +++---- src/native/mono/monodroid/monodroid-glue.cc | 7 +++- src/native/mono/monodroid/osbridge.cc | 6 +-- .../mono/runtime-base/shared-constants.hh | 3 +- src/native/mono/shared/cpp-util.hh | 40 +++++++++++-------- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index d0885f77a05..160fe7fce2f 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -92,9 +92,7 @@ namespace xamarin::android::internal { static constexpr size_t assemblies_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator); static constexpr auto assemblies_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator); - - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; + static constexpr std::string_view assemblies_prefix { assemblies_prefix_array }; // We have two records for each assembly, for names with and without the extension static constexpr uint32_t assembly_store_index_entries_per_assembly = 2; @@ -107,14 +105,11 @@ namespace xamarin::android::internal { static constexpr size_t assembly_store_file_name_size = calc_size (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_name_array = concat_string_views (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array.data () }; + static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array }; static constexpr size_t assembly_store_file_path_size = calc_size(apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_path_array = concat_string_views (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array.data () }; + static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array }; static constexpr size_t dso_size_overhead = ArchiveDSOStubConfig::PayloadSectionOffset + (ArchiveDSOStubConfig::SectionHeaderEntryCount * ArchiveDSOStubConfig::SectionHeaderEntrySize); @@ -173,8 +168,8 @@ namespace xamarin::android::internal { abort_unless ( runtime_config_data_size < std::numeric_limits::max (), [] { - return Util::monodroid_strdup_printf ("Runtime config binary blob size exceeds %u bytes", - std::numeric_limits::max ()); + return detail::_format_message ("Runtime config binary blob size exceeds %u bytes", + std::numeric_limits::max ()); } ); size = static_cast(runtime_config_data_size); diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 8fb6ce9c0b8..135c296a61a 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -917,7 +917,10 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( registerType != nullptr, [&error] { - return Util::monodroid_strdup_printf("INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", mono_error_get_message (&error)); + return detail::_format_message ( + "INTERNAL ERROR: Unable to find Android.Runtime.JNIEnvInit.RegisterJniNatives! %s", + mono_error_get_message (&error) + ); } ); @@ -946,7 +949,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec abort_unless ( initialize != nullptr, [&error] { - return Util::monodroid_strdup_printf ( + return detail::_format_message ( "Failed to obtain unmanaged-callers-only pointer to the Android.Runtime.JNIEnvInit.Initialize method. %s", mono_error_get_message (&error) ); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index c189efd5754..919506d3fda 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -880,9 +880,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (j > 0) { abort_unless ( sccs [i]->is_alive, - [&i] { - return Util::monodroid_strdup_printf ("Bridge SCC at index %d must be alive", i); - } + [&i] { return detail::_format_message ("Bridge SCC at index %d must be alive", i); } ); } sccs [i]->is_alive = 1; @@ -910,7 +908,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } else { abort_unless ( !sccs [i]->is_alive, - [&i] { return Util::monodroid_strdup_printf ("Bridge SCC at index %d must NOT be alive", i); } + [&i] { return detail::_format_message ("Bridge SCC at index %d must NOT be alive", i); } ); } } diff --git a/src/native/mono/runtime-base/shared-constants.hh b/src/native/mono/runtime-base/shared-constants.hh index 942b41fc964..c64680b2f83 100644 --- a/src/native/mono/runtime-base/shared-constants.hh +++ b/src/native/mono/runtime-base/shared-constants.hh @@ -46,8 +46,7 @@ namespace xamarin::android::internal static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); public: - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY.data () }; + static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY }; static constexpr std::string_view MONO_SGEN_SO { "libmonosgen-2.0.so" }; static constexpr std::string_view MONO_SGEN_ARCH_SO { "libmonosgen-" __BITNESS__ "-2.0.so" }; static constexpr std::string_view OVERRIDE_DIRECTORY_NAME { ".__override__" }; diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index 311c00e9f27..f2f03b9d5b6 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -18,33 +19,33 @@ #include - -static inline void -do_abort_unless (const char* fmt, ...) -{ - va_list ap; +namespace xamarin::android::detail { + [[gnu::always_inline, gnu::flatten]] + static inline const char* + _format_message (const char *format, ...) noexcept + { + va_list ap; + va_start (ap, format); char *message; int ret = vasprintf (&message, format, ap); - xamarin::android::Helpers::abort_application (n == -1 ? "Unable to allocate memory for abort message" : message); + va_end (ap); + return ret == -1 ? "Out of memory" : message; + } } -// #define abort_unless(_condition_, _fmt_, ...) \ -// if (!(_condition_)) [[unlikely]] { \ -// do_abort_unless ("%s:%d (%s): " _fmt_, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ -// } - template F> [[gnu::always_inline, gnu::flatten]] static inline void abort_unless (bool condition, F&& get_message, std::source_location sloc = std::source_location::current ()) noexcept { + static_assert (std::is_same::type, const char*>::value, "get_message must return 'const char*'"); + if (condition) [[likely]] { return; } -// static_assert (std::is_same, char*>::value, "get_message must return 'char*'"); xamarin::android::Helpers::abort_application (std::invoke (get_message), true /* log_location */, sloc); } @@ -58,22 +59,27 @@ abort_unless (bool condition, const char *message, std::source_location sloc = s xamarin::android::Helpers::abort_application (message, true /* log_location */, sloc); } -// #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_) - template [[gnu::always_inline, gnu::flatten]] static inline void abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless (ptr != nullptr, "Parameter '%s' must be a valid pointer", sloc); + abort_unless ( + ptr != nullptr, + [&ptr_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", ptr_name); }, + sloc + ); } [[gnu::always_inline, gnu::flatten]] static inline void abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_location sloc = std::source_location::current ()) noexcept { - abort_unless (arg > 0, "Parameter '%s' must be a valid pointer", sloc); + abort_unless ( + arg > 0, + [&arg_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", arg_name); }, + sloc + ); } // Helper to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any From c5f82c8f5995f9ea3b537c0d5418ebd06c6457a6 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 7 Nov 2024 14:13:30 +0100 Subject: [PATCH 035/143] Making EmbeddedAssemblies a static type In process to remove object instances for a slightly faster startup --- src/native/mono/monodroid/embedded-assemblies.hh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 160fe7fce2f..6240cdc1597 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -208,8 +208,8 @@ namespace xamarin::android::internal { } private: - static const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; - static MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; + STATIC_IN_ANDROID_RELEASE const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; + STATIC_IN_ANDROID_RELEASE MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; static size_t register_from_apk (const char *apk_file, monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (const char *dir, bool look_for_mangled_names, monodroid_should_register should_register) noexcept; @@ -462,8 +462,8 @@ namespace xamarin::android::internal { static inline uint32_t number_of_zip_dso_entries = 0u; static inline bool need_to_scan_more_apks = true; - static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; - static inline xamarin::android::mutex assembly_decompress_mutex {}; + static inline AssemblyStoreIndexEntry *assembly_store_hashes; + static inline xamarin::android::mutex assembly_decompress_mutex; }; } From 7db34e484ae0b13bd5fb52eefccbe7dcb8ee520e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 13 Nov 2024 10:58:18 -0800 Subject: [PATCH 036/143] More move to static, more cleanup --- src/native/mono/monodroid/embedded-assemblies.hh | 4 ++-- src/native/mono/monodroid/globals.cc | 1 + src/native/mono/monodroid/globals.hh | 1 + src/native/mono/monodroid/internal-pinvokes.cc | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 6240cdc1597..466f9947c73 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -208,8 +208,8 @@ namespace xamarin::android::internal { } private: - STATIC_IN_ANDROID_RELEASE const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; - STATIC_IN_ANDROID_RELEASE MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; + static const char* typemap_managed_to_java (MonoType *type, MonoClass *klass, const uint8_t *mvid) noexcept; + static MonoReflectionType* typemap_java_to_managed (hash_t hash, const MonoString *java_type_name) noexcept; static size_t register_from_apk (const char *apk_file, monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (monodroid_should_register should_register) noexcept; static size_t register_from_filesystem (const char *dir, bool look_for_mangled_names, monodroid_should_register should_register) noexcept; diff --git a/src/native/mono/monodroid/globals.cc b/src/native/mono/monodroid/globals.cc index d5fdf4d08e4..7822952f8f0 100644 --- a/src/native/mono/monodroid/globals.cc +++ b/src/native/mono/monodroid/globals.cc @@ -4,6 +4,7 @@ using namespace xamarin::android; using namespace xamarin::android::internal; OSBridge osBridge; +MonodroidRuntime monodroidRuntime; Timing *timing = nullptr; Debug debug; diff --git a/src/native/mono/monodroid/globals.hh b/src/native/mono/monodroid/globals.hh index 046a0ff770f..6f1649d9796 100644 --- a/src/native/mono/monodroid/globals.hh +++ b/src/native/mono/monodroid/globals.hh @@ -11,6 +11,7 @@ extern xamarin::android::Debug debug; extern xamarin::android::internal::OSBridge osBridge; +extern xamarin::android::internal::MonodroidRuntime monodroidRuntime; extern xamarin::android::Timing *timing; #endif // !__GLOBALS_H diff --git a/src/native/mono/monodroid/internal-pinvokes.cc b/src/native/mono/monodroid/internal-pinvokes.cc index 7c3dbab4933..a23bec07cf4 100644 --- a/src/native/mono/monodroid/internal-pinvokes.cc +++ b/src/native/mono/monodroid/internal-pinvokes.cc @@ -18,7 +18,7 @@ int monodroid_embedded_assemblies_set_assemblies_prefix (const char *prefix) { EmbeddedAssemblies::set_assemblies_prefix (prefix); - return 0; + return 0; } void diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 135c296a61a..af51cec4348 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -1271,7 +1271,7 @@ MonodroidRuntime::create_and_initialize_domain (JNIEnv* env, jclass runtimeClass abort_unless (default_alc != nullptr, "Default AssemblyLoadContext not found"); EmbeddedAssemblies::install_preload_hooks_for_alc (); - log_debug (LOG_ASSEMBLY, "ALC hooks installed"sv); + log_debug (LOG_ASSEMBLY, "ALC hooks installed"); bool preload = (AndroidSystem::is_assembly_preload_enabled () || (is_running_on_desktop && force_preload_assemblies)); From 0bbc9db60efeb594cd0f23a980b1a81dad6e31ff Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 13 Nov 2024 14:50:37 -0800 Subject: [PATCH 037/143] MonodroidRuntime is static now --- src/native/mono/monodroid/globals.cc | 1 - src/native/mono/monodroid/globals.hh | 1 - 2 files changed, 2 deletions(-) diff --git a/src/native/mono/monodroid/globals.cc b/src/native/mono/monodroid/globals.cc index 7822952f8f0..d5fdf4d08e4 100644 --- a/src/native/mono/monodroid/globals.cc +++ b/src/native/mono/monodroid/globals.cc @@ -4,7 +4,6 @@ using namespace xamarin::android; using namespace xamarin::android::internal; OSBridge osBridge; -MonodroidRuntime monodroidRuntime; Timing *timing = nullptr; Debug debug; diff --git a/src/native/mono/monodroid/globals.hh b/src/native/mono/monodroid/globals.hh index 6f1649d9796..046a0ff770f 100644 --- a/src/native/mono/monodroid/globals.hh +++ b/src/native/mono/monodroid/globals.hh @@ -11,7 +11,6 @@ extern xamarin::android::Debug debug; extern xamarin::android::internal::OSBridge osBridge; -extern xamarin::android::internal::MonodroidRuntime monodroidRuntime; extern xamarin::android::Timing *timing; #endif // !__GLOBALS_H From 567842177ef2eb7ef5bbc82a0d9886ec65343300 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 13 Nov 2024 16:33:44 -0800 Subject: [PATCH 038/143] Buglets fixed --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 4 ++-- src/native/mono/monodroid/embedded-assemblies.hh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 2cb51ec75e2..54a0c7ab27a 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -267,7 +267,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& dynamic_local_string entry_name; bool assembly_store_found = false; - log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); + log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('%s')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -279,7 +279,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& continue; } - if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path)) { + if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path.data ())) { assembly_store_found = true; map_assembly_store (entry_name, state); continue; diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 466f9947c73..160fe7fce2f 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -462,8 +462,8 @@ namespace xamarin::android::internal { static inline uint32_t number_of_zip_dso_entries = 0u; static inline bool need_to_scan_more_apks = true; - static inline AssemblyStoreIndexEntry *assembly_store_hashes; - static inline xamarin::android::mutex assembly_decompress_mutex; + static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; + static inline xamarin::android::mutex assembly_decompress_mutex {}; }; } From 44d4e55d73e1c6def0a86c37461c1c86fdbbd1e3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 21 Nov 2024 14:06:41 +0100 Subject: [PATCH 039/143] Trying to find out why AppContext.GetData doesn't appear to work --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 9 +++++++++ src/native/mono/monodroid/monodroid-glue.cc | 5 ++++- src/native/mono/runtime-base/shared-constants.hh | 5 +++-- src/native/mono/runtime-base/util.hh | 5 +++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 54a0c7ab27a..925f64ff8cd 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -47,6 +47,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vectorstart_event (TimingEventKind::RuntimeConfigBlob); @@ -720,7 +721,9 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks runtime_config_args.kind = 1; EmbeddedAssemblies::get_runtime_config_blob (runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); - monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); + log_info (LOG_ASSEMBLY, " rc data == %p; rc size == %zu", runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); + int ret = monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); + log_info (LOG_ASSEMBLY, " ret == %d", ret); if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (blob_time_index); diff --git a/src/native/mono/runtime-base/shared-constants.hh b/src/native/mono/runtime-base/shared-constants.hh index c64680b2f83..3c4261af61e 100644 --- a/src/native/mono/runtime-base/shared-constants.hh +++ b/src/native/mono/runtime-base/shared-constants.hh @@ -40,13 +40,14 @@ namespace xamarin::android::internal static constexpr std::string_view DLL_EXTENSION { ".dll" }; static constexpr std::string_view PDB_EXTENSION { ".pdb" }; - private: +// private: static constexpr std::string_view RUNTIME_CONFIG_BLOB_BASE_NAME { "libarc.bin" }; static constexpr size_t runtime_config_blob_name_size = calc_size (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); public: - static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY }; + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY.data () }; static constexpr std::string_view MONO_SGEN_SO { "libmonosgen-2.0.so" }; static constexpr std::string_view MONO_SGEN_ARCH_SO { "libmonosgen-" __BITNESS__ "-2.0.so" }; static constexpr std::string_view OVERRIDE_DIRECTORY_NAME { ".__override__" }; diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 3dbdeae10bc..ea2b9f72f4e 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -168,6 +168,11 @@ namespace xamarin::android return false; } + log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", + str.get () + str.length () - sv.length (), + sv.data (), + sv.length () + ); return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; } From 118b664ed2bf21f3ea01f0e74b7894b7c38cd561 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 21 Nov 2024 18:11:21 +0100 Subject: [PATCH 040/143] Cleanup --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 9 --------- src/native/mono/monodroid/embedded-assemblies.hh | 11 ++++++++--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 925f64ff8cd..54a0c7ab27a 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -47,7 +47,6 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator); - static constexpr std::string_view assemblies_prefix { assemblies_prefix_array }; + + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; // We have two records for each assembly, for names with and without the extension static constexpr uint32_t assembly_store_index_entries_per_assembly = 2; @@ -105,11 +107,14 @@ namespace xamarin::android::internal { static constexpr size_t assembly_store_file_name_size = calc_size (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_name_array = concat_string_views (assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array }; + + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array.data () }; static constexpr size_t assembly_store_file_path_size = calc_size(apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); static constexpr auto assembly_store_file_path_array = concat_string_views (apk_lib_dir_name, zip_path_separator, SharedConstants::android_lib_abi, zip_path_separator, assembly_store_prefix, SharedConstants::android_lib_abi, assembly_store_extension, dso_suffix); - static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array }; + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array.data () }; static constexpr size_t dso_size_overhead = ArchiveDSOStubConfig::PayloadSectionOffset + (ArchiveDSOStubConfig::SectionHeaderEntryCount * ArchiveDSOStubConfig::SectionHeaderEntrySize); From ecf77d89f8659eb8b3fc13bf7d39ab98439511e3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 25 Nov 2024 13:19:09 +0100 Subject: [PATCH 041/143] Lengths and offsets... --- src/native/mono/monodroid/internal-pinvokes.cc | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 5 +---- src/native/mono/runtime-base/shared-constants.hh | 2 +- src/native/mono/runtime-base/util.hh | 10 +++++----- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/native/mono/monodroid/internal-pinvokes.cc b/src/native/mono/monodroid/internal-pinvokes.cc index a23bec07cf4..7c3dbab4933 100644 --- a/src/native/mono/monodroid/internal-pinvokes.cc +++ b/src/native/mono/monodroid/internal-pinvokes.cc @@ -18,7 +18,7 @@ int monodroid_embedded_assemblies_set_assemblies_prefix (const char *prefix) { EmbeddedAssemblies::set_assemblies_prefix (prefix); - return 0; + return 0; } void diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 7e376ca9c3f..af51cec4348 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -713,7 +713,6 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks gather_bundled_assemblies (runtimeApks, &user_assemblies_count, have_split_apks); if (EmbeddedAssemblies::have_runtime_config_blob ()) { - log_info (LOG_ASSEMBLY, "Got runtime config blob"); size_t blob_time_index; if (FastTiming::enabled ()) [[unlikely]] { blob_time_index = internal_timing->start_event (TimingEventKind::RuntimeConfigBlob); @@ -721,9 +720,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks runtime_config_args.kind = 1; EmbeddedAssemblies::get_runtime_config_blob (runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); - log_info (LOG_ASSEMBLY, " rc data == %p; rc size == %zu", runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); - int ret = monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); - log_info (LOG_ASSEMBLY, " ret == %d", ret); + monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (blob_time_index); diff --git a/src/native/mono/runtime-base/shared-constants.hh b/src/native/mono/runtime-base/shared-constants.hh index 3c4261af61e..942b41fc964 100644 --- a/src/native/mono/runtime-base/shared-constants.hh +++ b/src/native/mono/runtime-base/shared-constants.hh @@ -40,7 +40,7 @@ namespace xamarin::android::internal static constexpr std::string_view DLL_EXTENSION { ".dll" }; static constexpr std::string_view PDB_EXTENSION { ".pdb" }; -// private: + private: static constexpr std::string_view RUNTIME_CONFIG_BLOB_BASE_NAME { "libarc.bin" }; static constexpr size_t runtime_config_blob_name_size = calc_size (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index ea2b9f72f4e..edd0e02f5ae 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -168,11 +168,11 @@ namespace xamarin::android return false; } - log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", - str.get () + str.length () - sv.length (), - sv.data (), - sv.length () - ); + // log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", + // str.get () + str.length () - sv.length (), + // sv.data (), + // sv.length () + // ); return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; } From 76cfa0d7fbcaa682eb6e7c17976786583e69383d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 09:51:09 +0100 Subject: [PATCH 042/143] Cleanup --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 2 +- src/native/mono/runtime-base/util.hh | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 54a0c7ab27a..bf6a4efc305 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -279,7 +279,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& continue; } - if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path.data ())) { + if (!assembly_store_found && Util::ends_with (entry_name, assembly_store_file_path)) { assembly_store_found = true; map_assembly_store (entry_name, state); continue; diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index edd0e02f5ae..3dbdeae10bc 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -168,11 +168,6 @@ namespace xamarin::android return false; } - // log_debug (LOG_ASSEMBLY, " ends_with: '%s' -> '%s'; sv.length () == %zu", - // str.get () + str.length () - sv.length (), - // sv.data (), - // sv.length () - // ); return memcmp (str.get () + str.length () - sv.length (), sv.data (), sv.length ()) == 0; } From f4b9cdbddc31b43d427aa19c81b43f6f877b94f1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 19:02:12 +0100 Subject: [PATCH 043/143] Start using std::format and std::string_view string literals --- src/native-clr/include/shared/log_level.hh | 133 ++++++++ .../mono/monodroid/embedded-assemblies-zip.cc | 76 ++--- .../mono/monodroid/embedded-assemblies.cc | 287 +++++++----------- .../mono/monodroid/embedded-assemblies.hh | 6 +- 4 files changed, 279 insertions(+), 223 deletions(-) diff --git a/src/native-clr/include/shared/log_level.hh b/src/native-clr/include/shared/log_level.hh index fc7a7566910..285255f649d 100644 --- a/src/native-clr/include/shared/log_level.hh +++ b/src/native-clr/include/shared/log_level.hh @@ -1,8 +1,34 @@ #pragma once #include +#include +#include +#include + +#include "java-interop-logger.h" + +// We redeclare macros as real functions here +#if defined(DO_LOG) +#undef DO_LOG +#endif + +#if defined(log_debug) +#undef log_debug +#endif + +#if defined(log_info) +#undef log_info +#endif namespace xamarin::android { + namespace detail { + [[gnu::always_inline]] + static inline bool _category_is_enabled (LogCategories category) noexcept + { + return (log_categories & category) == category; + } + } + enum class LogTimingCategories : uint32_t { Default = 0, @@ -23,4 +49,111 @@ namespace xamarin::android { 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; + + template [[gnu::always_inline]] + static inline constexpr void log_debug (LogCategories category, const char *format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_debug_nocheck (category, format, std::forward(args)...); + } + } + + template [[gnu::always_inline]] + static inline constexpr void log_debug (LogCategories category, std::string_view const& format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_debug_nocheck (category, format.data (), std::forward(args)...); + } + } + + static inline constexpr void log_debug (LogCategories category, std::string const& message) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_debug_nocheck (category, message.c_str ()); + } + } + + // + // This will be enabled once all log_* calls are converted to std::format format + // + // template [[gnu::always_inline]] + // static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) + // { + // if (detail::_category_is_enabled (category)) { + + // log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); + // } + // } + + template [[gnu::always_inline]] + static inline constexpr void log_info (LogCategories category, const char *format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, format, std::forward(args)...); + } + } + + template [[gnu::always_inline]] + static inline constexpr void log_info (LogCategories category, std::string_view const& format, Args&& ...args) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, format.data (), std::forward(args)...); + } + } + + [[gnu::always_inline]] + static inline constexpr void log_info (LogCategories category, std::string const& message) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, message.c_str ()); + } + } + + [[gnu::always_inline]] + static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept + { + if (detail::_category_is_enabled (category)) { + ::log_info_nocheck (category, message.c_str ()); + } + } + + [[gnu::always_inline]] + static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept + { + ::log_warn (category, message.c_str ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept + { + ::log_warn (category, message.data ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept + { + ::log_error (category, message.c_str ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept + { + ::log_error (category, message.data ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept + { + ::log_fatal (category, message.c_str ()); + } + + [[gnu::always_inline]] + static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept + { + ::log_fatal (category, message.data ()); + } } diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index bf6a4efc305..60a0658786f 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -22,7 +22,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector } auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (assembly_store_map, entry_name.get ()); - log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); + log_debug (LOG_ASSEMBLY, std::format ("Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size)); auto header = static_cast(payload_start); if (header->magic != ASSEMBLY_STORE_MAGIC) { @@ -227,7 +224,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string LOG_ASSEMBLY, std::format ( "Assembly store '{}' is not a valid .NET for Android assembly store file", - optional_string (entry_name.get ()) + entry_name.get () ) ); } @@ -237,7 +234,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string LOG_ASSEMBLY, std::format ( "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", - optional_string (entry_name.get ()), + entry_name.get (), header->version, ASSEMBLY_STORE_FORMAT_VERSION ) @@ -267,7 +264,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& dynamic_local_string entry_name; bool assembly_store_found = false; - log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('%s')", assembly_store_file_path.data ()); + log_debug (LOG_ASSEMBLY, std::format ("Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ())); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -303,12 +300,14 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& log_debug ( LOG_ASSEMBLY, - "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", - optional_string (entry_name.get ()), - number_of_zip_dso_entries, - optional_string (name), - apk_entry->name_hash, - apk_entry->offset + std::format ( + "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", + entry_name.get (), + number_of_zip_dso_entries, + name, + apk_entry->name_hash, + apk_entry->offset + ) ); number_of_zip_dso_entries++; } @@ -412,10 +411,9 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, - "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", - optional_string (entry.file_name), - optional_string (entry.name), - entry.data_size + std::format ("Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", + entry.file_name, entry.name, entry.data_size + ) ); } @@ -437,14 +435,14 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ // The simplest case - no file comment off_t ret = ::lseek (fd, -ZIP_EOCD_LEN, SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); return false; } std::array eocd; ssize_t nread = ::read (fd, eocd.data (), eocd.size ()); if (nread < 0 || nread != eocd.size ()) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); return false; } @@ -464,7 +462,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed ret = ::lseek (fd, static_cast(-alloc_size), SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); return false; } @@ -473,7 +471,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ nread = ::read (fd, buf.data (), buf.size ()); if (nread < 0 || static_cast(nread) != alloc_size) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); return false; } @@ -507,8 +505,10 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no if (result < 0) { log_error ( LOG_ASSEMBLY, - "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", - state.local_header_offset, std::strerror (errno), result, errno + std::format ( + "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", + state.local_header_offset, std::strerror (errno), result, errno + ) ); return false; } @@ -518,32 +518,32 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); if (nread < 0 || nread != ZIP_LOCAL_LEN) { - log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, std::format ("Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno)); return false; } size_t index = 0; if (!zip_read_field (local_header, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header entry signature at offset {}", state.local_header_offset)); return false; } if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, std::format ("Invalid Local Header entry signature at offset {}", state.local_header_offset)); return false; } uint16_t file_name_length; index = LH_FILE_NAME_LENGTH_OFFSET; if (!zip_read_field (local_header, index, file_name_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index))); return false; } uint16_t extra_field_length; index = LH_EXTRA_LENGTH_OFFSET; if (!zip_read_field (local_header, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index))); return false; } @@ -585,7 +585,7 @@ force_inline bool EmbeddedAssemblies::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { - log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); + log_error (LOG_ASSEMBLY, std::format ("Buffer too short to read {} bytes of data", to_read)); return false; } diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 95582ce2cc6..1ce0d2b1dbb 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -124,13 +124,13 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!", - optional_string (name), + name, cad.uncompressed_file_size, header->uncompressed_length ) ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", optional_string (name)); + log_debug (LOG_ASSEMBLY, std::format ("Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name)); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -143,7 +143,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} failed with code {}", - optional_string (name), + name, ret ) ); @@ -154,7 +154,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} yielded a different size (expected {}, got {})", - optional_string (name), + name, cad.uncompressed_file_size, static_cast(ret) ) @@ -228,7 +228,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", optional_string (file.name)); + log_debug (LOG_ASSEMBLY, std::format ("Assembly {} already mmapped by another thread, unmapping our copy", file.name)); munmap (map_info.area, file.data_size); map_info.area = nullptr; } @@ -243,16 +243,18 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc header[j] = isprint (p [j]) ? p [j] : '.'; header [header.size () - 1] = '\0'; - log_info_nocheck_fmt ( + log_info_nocheck ( LOG_ASSEMBLY, - "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", - file.data_offset, - static_cast(file.data), - pointer_add (file.data, file.data_size), - file.data_size, - optional_string (file.name), - optional_string (file.name), - header.data () + std::format ( + "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", + file.data_offset, + static_cast(file.data), + reinterpret_cast(file.data + file.data_size), + file.data_size, + file.name, + file.name, + header.data () + ) ); } } @@ -287,7 +289,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (strcmp (assembly.name, abi_name.get ()) != 0) { return nullptr; } else { - log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", optional_string (abi_name.get ())); + log_debug (LOG_ASSEMBLY, std::format ("open_from_bundles: found architecture-specific: '{}'", abi_name.get ())); } } @@ -321,7 +323,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (debug_file.data != nullptr) { if (debug_file.data_size > std::numeric_limits::max ()) { - log_warn (LOG_ASSEMBLY, "Debug info file '{}' is too big for Mono to consume", optional_string (debug_file.name)); + log_warn (LOG_ASSEMBLY, std::format ("Debug info file '{}' is too big for Mono to consume", debug_file.name)); } else { mono_debug_open_image_from_memory (image, reinterpret_cast(debug_file.data), static_cast(debug_file.data_size)); } @@ -333,7 +335,7 @@ EmbeddedAssemblies::load_bundled_assembly ( MonoImageOpenStatus status; MonoAssembly *a = mono_assembly_load_from_full (image, name.get (), &status, ref_only); if (a == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (name.get ()), optional_string (mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", name.get (), mono_image_strerror (status))); return nullptr; } @@ -348,7 +350,7 @@ EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_strin name.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", optional_string (name.get ())); + log_debug (LOG_ASSEMBLY, std::format ("individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ())); dynamic_local_string abi_name; abi_name @@ -395,11 +397,11 @@ template EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { hash_t name_hash = xxhash::hash (name.get (), name.length ()); - log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", optional_string (name.get ()), name_hash); + log_debug (LOG_ASSEMBLY, std::format ("assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash)); const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) { - log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.get ()), name_hash); + log_warn (LOG_ASSEMBLY, std::format ("Assembly '{}' (hash {:x}) not found", name.get (), name_hash)); return nullptr; } @@ -428,15 +430,16 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string(assembly_runtime_info.image_data), - static_cast(assembly_runtime_info.debug_info_data), - static_cast(assembly_runtime_info.config_data), - static_cast(assembly_runtime_info.descriptor), - assembly_runtime_info.descriptor->data_size, - assembly_runtime_info.descriptor->debug_data_size, - assembly_runtime_info.descriptor->config_data_size, - optional_string (name.get ()) + std::format ("Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'", + static_cast(assembly_runtime_info.image_data), + static_cast(assembly_runtime_info.debug_info_data), + static_cast(assembly_runtime_info.config_data), + static_cast(assembly_runtime_info.descriptor), + assembly_runtime_info.descriptor->data_size, + assembly_runtime_info.descriptor->debug_data_size, + assembly_runtime_info.descriptor->config_data_size, + name.get () + ) ); } @@ -446,7 +449,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string 0) { @@ -620,26 +623,26 @@ EmbeddedAssemblies::typemap_java_to_managed ([[maybe_unused]] hash_t hash, const entry = binary_search (java_type_name.get (), type_map.java_to_managed, type_map.entry_count); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ())); return nullptr; } const char *managed_type_name = entry->to; if (managed_type_name == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ()); + log_debug (LOG_ASSEMBLY, std::format ("typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ())); return nullptr; } - log_debug (LOG_DEFAULT, "typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), optional_string (managed_type_name)); + log_debug (LOG_DEFAULT, std::format ("typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), managed_type_name)); MonoType *type = mono_reflection_type_from_name (const_cast(managed_type_name), nullptr); if (type == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", optional_string (managed_type_name), java_type_name.get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ())); return nullptr; } 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 '{}'", optional_string (managed_type_name)); + log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type '{}'", managed_type_name)); return nullptr; } @@ -659,16 +662,16 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java TypeMapModule *module = java_entry != nullptr && java_entry->module_index < map_module_count ? &map_modules[java_entry->module_index] : nullptr; if (module == nullptr) { if (java_entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash)); } else { - log_warn (LOG_ASSEMBLY, "typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index); + log_warn (LOG_ASSEMBLY, std::format ("typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index)); } return nullptr; } const TypeMapModuleEntry *entry = binary_search (java_entry->type_token_id, module->map, module->entry_count); if (entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ())); return nullptr; } @@ -676,14 +679,14 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java module->image = mono_image_loaded (module->assembly_name); if (module->image == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", optional_string (module->assembly_name)); + log_debug (LOG_ASSEMBLY, std::format ("typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name)); // Fake a request from MonoVM to load the assembly. MonoAssemblyName *assembly_name = mono_assembly_name_new (module->assembly_name); MonoAssembly *assm; if (assembly_name == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: failed to create Mono assembly name for '{}'", optional_string (module->assembly_name)); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to create Mono assembly name for '{}'", module->assembly_name)); assm = nullptr; } else { MonoAssemblyLoadContextGCHandle alc_gchandle = mono_alc_get_default_gchandle (); @@ -692,28 +695,22 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (assm == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: failed to load managed assembly '{}'", optional_string (module->assembly_name)); + log_warn (LOG_ASSEMBLY, std::format ("typemap: failed to load managed assembly '{}'", module->assembly_name)); } else { module->image = mono_assembly_get_image (assm); } } if (module->image == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", optional_string (module->assembly_name), to_utf8 (java_type_name).get ()); + log_error (LOG_ASSEMBLY, std::format ("typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ())); return nullptr; } } - log_debug (LOG_ASSEMBLY, "typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); + log_debug (LOG_ASSEMBLY, std::format ("typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id)); MonoClass *klass = mono_class_get (module->image, java_entry->type_token_id); if (klass == nullptr) [[unlikely]] { - log_error ( - LOG_ASSEMBLY, - "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", - java_entry->type_token_id, - optional_string (module->assembly_name), - to_utf8 (java_type_name).get () - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); return nullptr; } @@ -724,12 +721,7 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java MonoReflectionType *ret = mono_type_get_object (domain, mono_class_get_type (klass)); if (ret == nullptr) { - log_warn (LOG_ASSEMBLY, - "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", - java_entry->type_token_id, - optional_string (module->assembly_name), - to_utf8 (java_type_name).get () - ); + log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); return nullptr; } @@ -794,7 +786,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapEntry *entry = typemap_managed_to_java (full_name.get ()); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", optional_string (full_name.get ())); + log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ())); return nullptr; } @@ -815,73 +807,57 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo if (mvid == nullptr) { log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); } else { - log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ()); + log_info (LOG_ASSEMBLY, std::format ("typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ())); } return nullptr; } uint32_t token = mono_class_get_type_token (klass); - log_debug (LOG_ASSEMBLY, "typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF); + log_debug (LOG_ASSEMBLY, std::format ("typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF)); // Each map entry is a pair of 32-bit integers: [TypeTokenID][JavaMapArrayIndex] const TypeMapModuleEntry *entry = match->map != nullptr ? binary_search (token, match->map, match->entry_count) : nullptr; if (entry == nullptr) { if (match->map == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ()); + log_warn (LOG_ASSEMBLY, std::format ("typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ())); return nullptr; } if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token); + log_debug (LOG_ASSEMBLY, std::format ("typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token)); entry = binary_search (token, match->duplicate_map, match->duplicate_count); } if (entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name); + log_info (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name)); return nullptr; } } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warn ( - LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", - token, - token, - MonoGuidString (mvid).get (), - optional_string (match->assembly_name), - entry->java_map_index - ); + log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index)); return nullptr; } TypeMapJava const& java_entry = map_java[entry->java_map_index]; if (java_entry.java_name_index >= java_type_count) [[unlikely]] { - log_warn ( - LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", - token, - token, - MonoGuidString (mvid).get (), - optional_string (match->assembly_name), - entry->java_map_index, - java_entry.java_name_index - ); + log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index)); return nullptr; } const char *ret = java_type_names[java_entry.java_name_index]; if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}", entry->java_map_index); + log_warn (LOG_ASSEMBLY, std::format ("typemap: empty Java type name returned for entry at index {}", entry->java_map_index)); } log_debug ( LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", - token, - token, - MonoGuidString (mvid).get (), - optional_string (match->assembly_name), - ret + std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", + token, + token, + MonoGuidString (mvid).get (), + match->assembly_name, + ret + ) ); return ret; @@ -943,15 +919,16 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons log_info ( LOG_ASSEMBLY, - " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + std::format (" mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", mmap_info.area, - pointer_add (mmap_info.area, mmap_info.size), + reinterpret_cast(reinterpret_cast (mmap_info.area) + mmap_info.size), mmap_info.size, file_info.area, - pointer_add (file_info.area, file_info.size), + reinterpret_cast(reinterpret_cast (file_info.area) + file_info.size), file_info.size, fd, - optional_string (filename) + filename + ) ); return file_info; @@ -967,11 +944,11 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro LOG_ASSEMBLY, std::format ( "ERROR: Unable to load application package {}.", - optional_string (apk) + apk ) ); } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk), fd); + log_debug (LOG_ASSEMBLY, std::format ("APK {} FD: {}", apk, fd)); zip_load_entries (fd, apk, should_register); } @@ -998,90 +975,40 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char struct stat sbuf; int res = fstatat (dir_fd, file_path, &sbuf, 0); if (res < 0) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to stat {} file '{}/{}': {}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); return false; } file_size = static_cast(sbuf.st_size); if (file_size < sizeof (header)) { - log_error ( - LOG_ASSEMBLY, - "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - sizeof (header) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header))); return false; } fd = openat (dir_fd, file_path, O_RDONLY); if (fd < 0) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to open {} file {}/{} for reading: {}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno))); return false; } ssize_t nread = do_read (fd, &header, sizeof (header)); if (nread <= 0) { if (nread < 0) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to read {} file header from '{}/{}': {}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); } else { - log_error ( - LOG_ASSEMBLY, - "typemap: end of file while reading {} file header from '{}/{}'", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path)); } return false; } if (header.magic != expected_magic) { - log_error ( - LOG_ASSEMBLY, - "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", - optional_string (file_type), - optional_string (dir_path), - optional_string (file_path), - expected_magic, - header.magic - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic)); return false; } if (header.version != MODULE_FORMAT_VERSION) { - log_error ( - LOG_ASSEMBLY, - "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", - optional_string (file_type), - MODULE_FORMAT_VERSION, - optional_string (dir_path), - optional_string (file_path), - header.version - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version)); return false; } @@ -1094,14 +1021,14 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ size_t entry_size = header.module_file_name_width; size_t data_size = entry_size * type_map_count; if (sizeof(header) + data_size > file_size) { - log_error (LOG_ASSEMBLY, "typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size); + log_error (LOG_ASSEMBLY, std::format ("typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size)); return nullptr; } auto data = std::make_unique (data_size); ssize_t nread = do_read (index_fd, data.get (), data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno)); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno))); return nullptr; } @@ -1117,7 +1044,7 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ std::unique_ptr EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", optional_string (dir_path), optional_string (index_path)); + log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap index file '{}/{}'", dir_path, index_path)); TypeMapIndexHeader header; size_t file_size; @@ -1144,13 +1071,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * ssize_t nread = do_read (file_fd, module.assembly_name, header.assembly_name_length); if (nread != static_cast(header.assembly_name_length)) { - log_error ( - LOG_ASSEMBLY, - "typemap: failed to read map assembly name from '{}/{}': {}", - optional_string (dir_path), - optional_string (file_path), - strerror (errno) - ); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno))); return false; } @@ -1159,14 +1080,16 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, - "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", - optional_string (dir_path), - optional_string (file_path), - header.entry_count, - header.java_name_width, - header.managed_name_width, - header.assembly_name_length, - optional_string (module.assembly_name) + std::format ( + "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", + dir_path, + file_path, + header.entry_count, + header.java_name_width, + header.managed_name_width, + header.assembly_name_length, + module.assembly_name + ) ); // [name][index] @@ -1180,7 +1103,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * module.data = new uint8_t [data_size]; nread = do_read (file_fd, module.data, data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", optional_string (dir_path), optional_string (file_path), strerror (errno)); + log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno))); return false; } @@ -1224,7 +1147,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * bool EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMap &module) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", optional_string (dir_path), optional_string (file_path)); + log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap file '{}/{}'", dir_path, file_path)); bool ret = true; BinaryTypeMapHeader header; @@ -1263,7 +1186,7 @@ EmbeddedAssemblies::register_from_apk (const char *apk_file, monodroid_should_re gather_bundled_assemblies_from_apk (apk_file, should_register); - log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", optional_string (apk_file), number_of_found_assemblies - prev); + log_info (LOG_ASSEMBLY, std::format ("Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev)); return number_of_found_assemblies; } @@ -1367,10 +1290,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( [[gnu::always_inline]] size_t EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look_for_mangled_names, monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", optional_string (lib_dir_path)); + log_debug (LOG_ASSEMBLY, std::format ("Looking for assemblies in '{}'", lib_dir_path)); DIR *lib_dir = opendir (lib_dir_path); // TODO: put it in a scope guard at some point if (lib_dir == nullptr) { - log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno))); return 0; } @@ -1379,14 +1302,14 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno))); closedir (lib_dir); return 0; } state.file_fd = dup (dir_fd); if (state.file_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno))); closedir (lib_dir); return 0; } @@ -1403,7 +1326,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno))); continue; // keep going, no harm } break; // No more entries, we're done @@ -1423,7 +1346,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look // ...and we can handle the runtime config entry if (!runtime_config_blob_found && std::strncmp (cur->d_name, SharedConstants::RUNTIME_CONFIG_BLOB_NAME.data (), SharedConstants::RUNTIME_CONFIG_BLOB_NAME.size ()) == 0) { - log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", optional_string (cur->d_name)); + log_debug (LOG_ASSEMBLY, std::format ("Mapping runtime config blob from '{}'", cur->d_name)); auto file_size = Util::get_file_size_at (state.file_fd, cur->d_name); if (!file_size) { continue; @@ -1470,6 +1393,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, "Found {} assemblies on the filesystem", assembly_count); + log_debug (LOG_ASSEMBLY, std::format ("Found {} assemblies on the filesystem", assembly_count)); return assembly_count; } diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index bbb91157b10..fe7493506fa 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -310,7 +310,7 @@ namespace xamarin::android::internal { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", optional_string (file_name)); + log_debug (LOG_ASSEMBLY, std::format ("Not an ELF image: {}", file_name)); // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } @@ -329,7 +329,7 @@ namespace xamarin::android::internal { static void store_mapped_runtime_config_data (md_mmap_info const& map_info, const char *file_name) noexcept { auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (map_info, file_name); - log_debug (LOG_ASSEMBLY, "Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size); + log_debug (LOG_ASSEMBLY, std::format ("Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size)); runtime_config_data = payload_start; runtime_config_data_size = payload_size; runtime_config_blob_found = true; @@ -436,7 +436,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", optional_string (name.get ())); + log_debug (LOG_ASSEMBLY, std::format ("Unmangled name to '{}'", name.get ())); }; private: From 3938562acf2e527fd3d8a41f379b4b8cead3533c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 26 Nov 2024 22:55:24 +0100 Subject: [PATCH 044/143] A bit less of reinterpret_cast<> --- src/native/mono/monodroid/embedded-assemblies.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 1ce0d2b1dbb..2e7580dd398 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -249,7 +249,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", file.data_offset, static_cast(file.data), - reinterpret_cast(file.data + file.data_size), + pointer_add (file.data, file.data_size), file.data_size, file.name, file.name, @@ -921,10 +921,10 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons LOG_ASSEMBLY, std::format (" mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", mmap_info.area, - reinterpret_cast(reinterpret_cast (mmap_info.area) + mmap_info.size), + pointer_add (mmap_info.area, mmap_info.size), mmap_info.size, file_info.area, - reinterpret_cast(reinterpret_cast (file_info.area) + file_info.size), + pointer_add (file_info.area, file_info.size), file_info.size, fd, filename From 6fe8dfc0dfa58222bd3cedb9db8d3e74207308e5 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 27 Nov 2024 13:13:47 +0100 Subject: [PATCH 045/143] Conversion to std::format continues Build is broken atm --- src/native-clr/include/shared/log_level.hh | 182 ++++++++---------- src/native/mono/monodroid/debug.cc | 61 +++--- .../mono/monodroid/embedded-assemblies-zip.cc | 6 +- src/native/mono/monodroid/monodroid-glue.cc | 79 ++++---- src/native/mono/monodroid/osbridge.cc | 161 +++++++++------- .../mono/monodroid/xamarin_getifaddrs.cc | 56 +++--- .../pinvoke-override-api-impl.hh | 12 +- .../mono/pinvoke-override/precompiled.cc | 12 +- .../mono/runtime-base/android-system.cc | 64 +++--- src/native/mono/runtime-base/monodroid-dl.hh | 12 +- 10 files changed, 315 insertions(+), 330 deletions(-) diff --git a/src/native-clr/include/shared/log_level.hh b/src/native-clr/include/shared/log_level.hh index 285255f649d..e11dc18dae9 100644 --- a/src/native-clr/include/shared/log_level.hh +++ b/src/native-clr/include/shared/log_level.hh @@ -7,11 +7,7 @@ #include "java-interop-logger.h" -// We redeclare macros as real functions here -#if defined(DO_LOG) -#undef DO_LOG -#endif - +// We redeclare macros here #if defined(log_debug) #undef log_debug #endif @@ -20,15 +16,17 @@ #undef log_info #endif -namespace xamarin::android { - namespace detail { - [[gnu::always_inline]] - static inline bool _category_is_enabled (LogCategories category) noexcept - { - return (log_categories & category) == category; - } - } +#define DO_LOG_FMT(_level, _category_, _message_) \ + do { \ + if ((log_categories & ((_category_))) != 0) { \ + ::log_ ## _level ## _nocheck ((_category_), _message_); \ + } \ + } while (0) + +#define log_debug(_category_, _message_) DO_LOG_FMT (debug, (_category_), (_message_)) +#define log_info(_category_, _message_) DO_LOG_FMT (info, (_category_), (_message_)) +namespace xamarin::android { enum class LogTimingCategories : uint32_t { Default = 0, @@ -53,107 +51,79 @@ namespace xamarin::android { // 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; +} - template [[gnu::always_inline]] - static inline constexpr void log_debug (LogCategories category, const char *format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_debug_nocheck (category, format, std::forward(args)...); - } - } - - template [[gnu::always_inline]] - static inline constexpr void log_debug (LogCategories category, std::string_view const& format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_debug_nocheck (category, format.data (), std::forward(args)...); - } - } - - static inline constexpr void log_debug (LogCategories category, std::string const& message) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_debug_nocheck (category, message.c_str ()); - } - } - - // - // This will be enabled once all log_* calls are converted to std::format format - // - // template [[gnu::always_inline]] - // static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) - // { - // if (detail::_category_is_enabled (category)) { - - // log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); - // } - // } - - template [[gnu::always_inline]] - static inline constexpr void log_info (LogCategories category, const char *format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, format, std::forward(args)...); - } - } +// +// This will be enabled once all log_* calls are converted to std::format format +// +// template [[gnu::always_inline]] +// static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) +// { +// if (detail::_category_is_enabled (category)) { + +// log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); +// } +// } + +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Debug, message.c_str ()); +} - template [[gnu::always_inline]] - static inline constexpr void log_info (LogCategories category, std::string_view const& format, Args&& ...args) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, format.data (), std::forward(args)...); - } - } +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Debug, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_info (LogCategories category, std::string const& message) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, message.c_str ()); - } - } +[[gnu::always_inline]] +static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Info, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept - { - if (detail::_category_is_enabled (category)) { - ::log_info_nocheck (category, message.c_str ()); - } - } +[[gnu::always_inline]] +static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Info, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept - { - ::log_warn (category, message.c_str ()); - } +[[gnu::always_inline]] +static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept - { - ::log_warn (category, message.data ()); - } +[[gnu::always_inline]] +static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept - { - ::log_error (category, message.c_str ()); - } +[[gnu::always_inline]] +static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept - { - ::log_error (category, message.data ()); - } +[[gnu::always_inline]] +static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, message.data ()); +} - [[gnu::always_inline]] - static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept - { - ::log_fatal (category, message.c_str ()); - } +[[gnu::always_inline]] +static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, message.c_str ()); +} - [[gnu::always_inline]] - static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept - { - ::log_fatal (category, message.data ()); - } +[[gnu::always_inline]] +static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); } + +extern unsigned int log_categories; +#endif // ndef LOG_LEVEL_HH diff --git a/src/native/mono/monodroid/debug.cc b/src/native/mono/monodroid/debug.cc index 492e114704b..18d355bfa84 100644 --- a/src/native/mono/monodroid/debug.cc +++ b/src/native/mono/monodroid/debug.cc @@ -95,9 +95,10 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (!found) log_warn (LOG_DEFAULT, - "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", - optional_string (mname.get ()), - optional_string (libname.get ()) + std::format ("The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", + mname.get (), + libname.get () + ) ); } @@ -109,7 +110,7 @@ bool Debug::load_profiler (void *handle, const char *desc, const char *symbol) { ProfilerInitializer func = reinterpret_cast (java_interop_lib_symbol (handle, symbol, nullptr)); - log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", optional_string (symbol), reinterpret_cast(func)); + log_warn (LOG_DEFAULT, std::format ("Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func))); if (func != nullptr) { func (desc); @@ -139,7 +140,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, "Connection options: '{}'", optional_string (options)); + log_info (LOG_DEFAULT, std::format ("Connection options: '{}'", options)); args = Util::monodroid_strsplit (options, ",", 0); @@ -149,12 +150,12 @@ Debug::parse_options (char *options, ConnOptions *opts) if (strstr (arg, "port=") == arg) { int port = atoi (arg + strlen ("port=")); if (port < 0 || port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid debug port value {}", port); + log_error (LOG_DEFAULT, std::format ("Invalid debug port value {}", port)); continue; } conn_port = static_cast(port); - log_info (LOG_DEFAULT, "XS port = {}", conn_port); + log_info (LOG_DEFAULT, std::format ("XS port = {}", conn_port)); } else if (strstr (arg, "timeout=") == arg) { char *endp; @@ -163,7 +164,7 @@ Debug::parse_options (char *options, ConnOptions *opts) if ((endp == arg) || (*endp != '\0')) log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, "Unknown connection option: '{}'", optional_string (arg)); + log_info (LOG_DEFAULT, std::format ("Unknown connection option: '{}'", arg)); } } } @@ -187,7 +188,7 @@ Debug::start_connection (char *options) cur_time = time (nullptr); if (opts.timeout_time && cur_time > opts.timeout_time) { - log_warn (LOG_DEBUGGER, "Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time); + log_warn (LOG_DEBUGGER, std::format ("Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time)); return DebuggerConnectionStatus::Unconnected; } @@ -198,7 +199,7 @@ Debug::start_connection (char *options) res = pthread_create (&conn_thread_id, nullptr, xamarin::android::conn_thread, this); if (res) { - log_error (LOG_DEFAULT, "Failed to create connection thread: {}", strerror (errno)); + log_error (LOG_DEFAULT, std::format ("Failed to create connection thread: {}", strerror (errno))); return DebuggerConnectionStatus::Error; } @@ -262,20 +263,20 @@ Debug::process_connection (int fd) return false; } if (rv <= 0) { - log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); return false; } rv = Util::recv_uninterrupted (fd, command, cmd_len); if (rv <= 0) { - log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); return false; } // null-terminate command [cmd_len] = 0; - log_info (LOG_DEFAULT, "Received cmd: '{}'.", optional_string (command)); + log_info (LOG_DEFAULT, std::format ("Received cmd: '{}'.", command)); if (process_cmd (fd, command)) return true; @@ -287,14 +288,14 @@ Debug::handle_server_connection (void) { int listen_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_socket == -1) { - log_info (LOG_DEFAULT, "Could not create socket for XS to connect to: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not create socket for XS to connect to: {}", strerror (errno))); return 1; } int flags = 1; int rv = setsockopt (listen_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); if (rv == -1 && Util::should_log (LOG_DEFAULT)) { - log_info_nocheck_fmt (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno)); + log_info_nocheck (LOG_DEFAULT, std::format ("Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno))); // not a fatal failure } @@ -308,7 +309,7 @@ Debug::handle_server_connection (void) listen_addr.sin_addr.s_addr = INADDR_ANY; rv = bind (listen_socket, (struct sockaddr *) &listen_addr, sizeof (listen_addr)); if (rv == -1) { - log_info (LOG_DEFAULT, "Could not bind to address: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not bind to address: {}", strerror (errno))); rv = 2; goto cleanup; } @@ -320,7 +321,7 @@ Debug::handle_server_connection (void) rv = listen (listen_socket, 1); if (rv == -1) { - log_info (LOG_DEFAULT, "Could not listen for XS: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not listen for XS: {}", strerror (errno))); rv = 2; goto cleanup; } @@ -370,7 +371,7 @@ Debug::handle_server_connection (void) } while (rv == -1 && errno == EINTR); if (rv == -1) { - log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Failed while waiting for XS to connect: {}", strerror (errno))); rv = 2; goto cleanup; } @@ -378,18 +379,18 @@ Debug::handle_server_connection (void) socklen_t len = sizeof (struct sockaddr_in); int fd = accept (listen_socket, (struct sockaddr *) &listen_addr, &len); if (fd == -1) { - log_info (LOG_DEFAULT, "Failed to accept connection from XS: {}", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Failed to accept connection from XS: {}", strerror (errno))); rv = 3; goto cleanup; } flags = 1; if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flags, sizeof (flags)) < 0) { - log_info (LOG_DEFAULT, "Could not set TCP_NODELAY on socket ({})", strerror (errno)); + log_info (LOG_DEFAULT, std::format ("Could not set TCP_NODELAY on socket ({})", strerror (errno))); // not a fatal failure } - log_info (LOG_DEFAULT, "Successfully received connection from XS on port {}, fd: {}", listen_port, fd); + log_info (LOG_DEFAULT, std::format ("Successfully received connection from XS on port {}, fd: {}", listen_port, fd)); need_new_conn = process_connection (fd); } @@ -441,7 +442,7 @@ Debug::process_cmd (int fd, char *cmd) constexpr std::string_view PONG_REPLY { "pong" }; if (strcmp (cmd, PING_CMD.data ()) == 0) { 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 ({})", strerror (errno)); + log_error (LOG_DEFAULT, std::format ("Got keepalive request from XS, but could not send response back ({})", strerror (errno))); return false; } @@ -487,7 +488,7 @@ Debug::process_cmd (int fd, char *cmd) profiler_fd = fd; profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { - log_error (LOG_DEFAULT, "Unknown profiler: '{}'", optional_string (prof)); + log_error (LOG_DEFAULT, std::format ("Unknown profiler: '{}'", prof)); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -496,7 +497,7 @@ Debug::process_cmd (int fd, char *cmd) pthread_mutex_unlock (&process_cmd_mutex); return use_fd; } else { - log_error (LOG_DEFAULT, "Unsupported command: '{}'", optional_string (cmd)); + log_error (LOG_DEFAULT, std::format ("Unsupported command: '{}'", cmd)); } return false; @@ -526,7 +527,7 @@ Debug::start_debugging (void) // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); + log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); if (enable_soft_breakpoints ()) { constexpr std::string_view soft_breakpoints { "--soft-breakpoints" }; @@ -553,7 +554,7 @@ Debug::start_profiling () if (!profiler_description) return; - log_info (LOG_DEFAULT, "Loading profiler: '{}'", profiler_description); + log_info (LOG_DEFAULT, std::format ("Loading profiler: '{}'", profiler_description)); monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), profiler_description, nullptr); } @@ -573,7 +574,7 @@ Debug::enable_soft_breakpoints (void) uname (&name); for (const char** ptr = soft_breakpoint_kernel_list; *ptr; ptr++) { if (strcmp (name.release, *ptr) == 0) { - log_info (LOG_DEBUGGER, "soft breakpoints enabled due to kernel version match ({})", name.release); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled due to kernel version match ({})", name.release)); return 1; } } @@ -581,17 +582,17 @@ Debug::enable_soft_breakpoints (void) char *value; /* Soft breakpoints are enabled by default */ if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS, &value) <= 0) { - log_info (LOG_DEBUGGER, "soft breakpoints enabled by default ({} property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled by default ({} 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 ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); } else { ret = true; - log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); + log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); } delete[] value; return ret; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 60a0658786f..59069330dfb 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -331,9 +331,9 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ); } #ifdef DEBUG - log_info (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); - log_info (LOG_ASSEMBLY, "Central directory size: {}", cd_size); - log_info (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); + log_info (LOG_ASSEMBLY, std::format ("Central directory offset: {}", cd_offset)); + log_info (LOG_ASSEMBLY, std::format ("Central directory size: {}", cd_size)); + log_info (LOG_ASSEMBLY, std::format ("Central directory entries: {}", cd_entries)); #endif off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); if (retval < 0) { diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index af51cec4348..65cf8919eea 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -174,12 +174,12 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] fullpath.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", optional_string (fullpath.get ())); + log_debug (LOG_ASSEMBLY, std::format ("open_from_update_dir: trying to open assembly: {}", 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) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (fullpath.get ()), mono_image_strerror (status)); + log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status))); } } else { log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); @@ -191,7 +191,7 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] } if (result != nullptr && Util::should_log (LOG_ASSEMBLY)) { - log_info_nocheck_fmt (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result)); + log_info_nocheck (LOG_ASSEMBLY, std::format ("open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result))); } return result; } @@ -378,7 +378,7 @@ MonodroidRuntime::parse_gdb_options () noexcept time_t secs = time (nullptr); if (v + 10 < secs) { - log_warn (LOG_DEFAULT, "Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); + log_warn (LOG_DEFAULT, std::format ("Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ())); do_wait = false; } } @@ -449,13 +449,13 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid SDB port value {}", sdb_port); + log_error (LOG_DEFAULT, std::format ("Invalid SDB port value {}", sdb_port)); ret = false; continue; } if (out_port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid output port value {}", out_port); + log_error (LOG_DEFAULT, std::format ("Invalid output port value {}", out_port)); ret = false; continue; } @@ -480,7 +480,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string arg (token); - log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", optional_string (arg.get ())); + log_error (LOG_DEFAULT, std::format ("Unknown runtime argument: '{}'", arg.get ())); ret = false; } } @@ -509,9 +509,9 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse cur_time = time (nullptr); if (!parse_runtime_args (runtime_args, &options)) { - log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", optional_string (runtime_args.get ())); + log_error (LOG_DEFAULT, std::format ("Failed to parse runtime args: '{}'", runtime_args.get ())); } else if (options.debug && cur_time > options.timeout_time) { - log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time); + log_warn (LOG_DEBUGGER, std::format ("Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time)); } else if (options.debug && cur_time <= options.timeout_time) { EmbeddedAssemblies::set_register_debug_symbols (true); @@ -537,7 +537,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); + log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); if (options.out_port > 0) { int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -570,13 +570,13 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (options.server) { int accepted = monodroid_debug_accept (sock, addr); - log_warn (LOG_DEBUGGER, "Accepted stdout connection: {}", accepted); + log_warn (LOG_DEBUGGER, std::format ("Accepted stdout connection: {}", accepted)); if (accepted < 0) { Helpers::abort_application ( LOG_DEBUGGER, std::format ( "Error accepting stdout and stderr ({}:{}): {}", - optional_string (options.host), + options.host, options.out_port, strerror (errno) ) @@ -591,7 +591,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse LOG_DEBUGGER, std::format ( "Error connecting stdout and stderr ({}:{}): {}", - optional_string (options.host), + options.host, options.out_port, strerror (errno) ) @@ -662,7 +662,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; - log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", optional_string (prop_val.get ())); + log_warn (LOG_DEBUGGER, std::format ("passing '{}' as extra arguments to the runtime.", prop_val.get ())); char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; @@ -730,9 +730,11 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks 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 '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", - optional_string (AndroidSystem::override_dirs [0]), - (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? optional_string (AndroidSystem::override_dirs [1]) : "" + std::format ( + "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", + AndroidSystem::override_dirs [0], + (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv + ) ); #else log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"sv); @@ -741,7 +743,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks Helpers::abort_application ( std::format ( "ALL entries in APK named `{}` MUST be STORED. Gradle's minification may COMPRESS such entries.", - optional_string (assemblies_prefix) + assemblies_prefix ) ); } @@ -857,7 +859,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec // GC threshold is 90% of the max GREF count init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); - log_info (LOG_GC, "GREF GC Threshold: {}", init.grefGcThreshold); + log_info (LOG_GC, std::format ("GREF GC Threshold: {}", init.grefGcThreshold)); init.grefClass = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); @@ -943,7 +945,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec auto initialize = reinterpret_cast (mono_method_get_unmanaged_callers_only_ftnptr (method, &error)); if (initialize == nullptr) { - log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", optional_string (mono_error_get_message (&error))); + log_fatal (LOG_DEFAULT, std::format ("Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error))); } abort_unless ( @@ -999,7 +1001,7 @@ MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstr if (createDirectory) { 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 {}. {}", optional_string (name), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create directory for environment variable {}. {}", name, strerror (errno))); } setenv (name, value.get_cstr (), 1); } @@ -1009,10 +1011,10 @@ MonodroidRuntime::create_xdg_directory (jstring_wrapper& home, size_t home_len, { static_local_string dir (home_len + 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: {}", optional_string (dir.get ())); + log_debug (LOG_DEFAULT, std::format ("Creating XDG directory: {}", dir.get ())); int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", optional_string (dir.get ()), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create XDG directory {}. {}", dir.get (), strerror (errno))); if (!environment_variable_name.empty ()) { setenv (environment_variable_name.data (), dir.get (), 1); } @@ -1041,7 +1043,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", optional_string (name), optional_string (v)); + log_debug (LOG_DEFAULT, std::format ("Env variable '{}' set to '{}'.", name, v)); }; string_segment arg_token; @@ -1061,7 +1063,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept log_envvar (arg.get (), one.data ()); } else if (index == 0) { // ’=value’ - log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", optional_string (arg.get ())); + log_warn (LOG_DEFAULT, std::format ("Attempt to set environment variable without specifying name: '{}'", arg.get ())); } else { // ’name=value’ arg[index] = '\0'; @@ -1141,10 +1143,10 @@ MonodroidRuntime::set_profile_options () noexcept .append (output_path.get (), output_path.length ()); } if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno))); } - log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", optional_string (value.get ())); + log_warn (LOG_DEFAULT, std::format ("Initializing profiler with options: {}", value.get ())); debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } @@ -1271,7 +1273,7 @@ MonodroidRuntime::create_and_initialize_domain (JNIEnv* env, jclass runtimeClass abort_unless (default_alc != nullptr, "Default AssemblyLoadContext not found"); EmbeddedAssemblies::install_preload_hooks_for_alc (); - log_debug (LOG_ASSEMBLY, "ALC hooks installed"); + log_debug (LOG_ASSEMBLY, "ALC hooks installed"sv); bool preload = (AndroidSystem::is_assembly_preload_enabled () || (is_running_on_desktop && force_preload_assemblies)); @@ -1469,7 +1471,7 @@ 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: {}", optional_string (AndroidSystem::get_runtime_libdir ())); + log_debug (LOG_DEFAULT, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); } AndroidSystem::setup_process_args (runtimeApks); @@ -1534,14 +1536,15 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (Util::should_log (LOG_DEFAULT)) [[unlikely]] { log_info_nocheck_fmt ( LOG_DEFAULT, - ".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", - BuildInfo::xa_version.data (), - BuildInfo::architecture.data (), - BuildInfo::kind.data (), - BuildInfo::date.data (), - BuildInfo::ndk_version.data (), - BuildInfo::ndk_api_level.data (), - mono_get_runtime_build_info () + std::format (".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", + BuildInfo::xa_version.data (), + BuildInfo::architecture.data (), + BuildInfo::kind.data (), + BuildInfo::date.data (), + BuildInfo::ndk_version.data (), + BuildInfo::ndk_api_level.data (), + mono_get_runtime_build_info () + ) ); } @@ -1664,7 +1667,7 @@ MonodroidRuntime::get_java_class_name_for_TypeManager (jclass klass) noexcept JNIEnv *env = osBridge.ensure_jnienv (); jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); if (name == nullptr) { - log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); + log_error (LOG_DEFAULT, std::format ("Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass))); return nullptr; } diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 919506d3fda..612e6c44c5e 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -186,7 +186,7 @@ OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) *end = '\0'; if ((category == LOG_GREF && gref_to_logcat) || (category == LOG_LREF && lref_to_logcat)) { - log_debug (category, "{}", optional_string (m)); + log_debug (category, std::format ("{}", m)); } if (to != nullptr) { fprintf (to, "%s\n", optional_string (m)); @@ -200,7 +200,7 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, "{}", optional_string (message)); + log_debug (LOG_GREF, std::format ("{}", message)); } if (!gref_log) return; @@ -214,23 +214,23 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH int c = _monodroid_gref_inc (); if ((log_categories & LOG_GREF) == 0) return c; - log_info (LOG_GREF, - "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - optional_string (threadName), - threadId + std::format ("+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -261,19 +261,20 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -300,21 +301,22 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - optional_string (threadName), - threadId + std::format ("+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -343,19 +345,20 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!gref_log) @@ -381,18 +384,19 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - "+l+ lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("+l+ lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!lref_log) @@ -417,18 +421,19 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - "-l- lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - optional_string (threadName), - threadId + std::format ("-l- lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId + ) ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, std::format ("{}", from)); } } if (!lref_log) @@ -541,9 +546,11 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) i = get_gc_bridge_index (klass); if (i == static_cast (-NUM_GC_BRIDGE_TYPES)) { log_info (LOG_GC, - "asked if a class {}.{} is a bridge before we inited java.lang.Object", - optional_string (mono_class_get_namespace (klass)), - optional_string (mono_class_get_name (klass)) + std::format ( + "asked if a class {}.{} is a bridge before we inited java.lang.Object", + mono_class_get_namespace (klass), + mono_class_get_name (klass) + ) ); return MonoGCBridgeObjectKind::GC_BRIDGE_TRANSPARENT_CLASS; } @@ -569,9 +576,11 @@ OSBridge::gc_is_bridge_object (MonoObject *object) #if DEBUG MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, - "object of class {}.{} with null handle", - optional_string (mono_class_get_namespace (mclass)), - optional_string (mono_class_get_name (mclass)) + std::format ( + "object of class {}.{} with null handle", + mono_class_get_namespace (mclass), + mono_class_get_name (mclass) + ) ); #endif return 0; @@ -658,9 +667,9 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri *reffed_description = describe_target (reffed_target); if (success) - log_warn (LOG_GC, "Added reference for {} to {}", optional_string (description), optional_string (reffed_description)); + log_warn (LOG_GC, std::format ("Added reference for {} to {}", description, reffed_description)); else - log_error (LOG_GC, "Missing monodroidAddReference method for {}", optional_string (description)); + log_error (LOG_GC, std::format ("Missing monodroidAddReference method for {}", description)); free (description); free (reffed_description); @@ -897,9 +906,11 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (Logger::gc_spew_enabled ()) { klass = mono_object_get_class (obj); log_error (LOG_GC, - "Missing monodroidClearReferences method for object of class {}.{}", - optional_string (mono_class_get_namespace (klass)), - optional_string (mono_class_get_name (klass)) + std::format ( + "Missing monodroidClearReferences method for object of class {}.{}", + mono_class_get_namespace (klass), + mono_class_get_name (klass) + ) ); } #endif @@ -914,7 +925,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } } #if DEBUG - log_info (LOG_GC, "GC cleanup summary: {} objects tested - resurrecting {}.", total, alive); + log_info (LOG_GC, std::format ("GC cleanup summary: {} objects tested - resurrecting {}.", total, alive)); #endif } @@ -944,10 +955,10 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre if (Logger::gc_spew_enabled ()) { int i, j; - log_info (LOG_GC, "cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs); + log_info (LOG_GC, std::format ("cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs)); for (i = 0; i < num_sccs; ++i) { - log_info (LOG_GC, "group {} with {} objects", i, sccs [i]->num_objs); + log_info (LOG_GC, std::format ("group {} with {} objects", i, sccs [i]->num_objs)); for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; @@ -962,19 +973,21 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre } MonoClass *klass = mono_object_get_class (obj); log_info (LOG_GC, - "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", - reinterpret_cast(obj), - optional_string (mono_class_get_namespace (klass)), - optional_string (mono_class_get_name (klass)), - reinterpret_cast(handle), - key_handle + std::format ( + "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", + reinterpret_cast(obj), + mono_class_get_namespace (klass), + mono_class_get_name (klass), + reinterpret_cast(handle), + key_handle + ) ); } } if (Util::should_log (LOG_GC)) { for (i = 0; i < num_xrefs; ++i) - log_info_nocheck_fmt (LOG_GC, "xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); + log_info_nocheck (LOG_GC, std::format ("xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index)); } } diff --git a/src/native/mono/monodroid/xamarin_getifaddrs.cc b/src/native/mono/monodroid/xamarin_getifaddrs.cc index 23848f9910b..99ba01039e6 100644 --- a/src/native/mono/monodroid/xamarin_getifaddrs.cc +++ b/src/native/mono/monodroid/xamarin_getifaddrs.cc @@ -421,7 +421,7 @@ open_netlink_session (netlink_session *session) memset (session, 0, sizeof (*session)); session->sock_fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (session->sock_fd == -1) { - log_warn (LOG_NETLINK, "Failed to create a netlink socket. {}", strerror (errno)); + log_warn (LOG_NETLINK, std::format ("Failed to create a netlink socket. {}", strerror (errno))); return -1; } @@ -440,7 +440,7 @@ open_netlink_session (netlink_session *session) session->them.nl_family = AF_NETLINK; if (bind (session->sock_fd, (struct sockaddr *)&session->us, sizeof (session->us)) < 0) { - log_warn (LOG_NETLINK, "Failed to bind to the netlink socket. {}", strerror (errno)); + log_warn (LOG_NETLINK, std::format ("Failed to bind to the netlink socket. {}", strerror (errno))); return -1; } @@ -478,7 +478,7 @@ send_netlink_dump_request (netlink_session *session, int type) session->message_header.msg_iov = &session->payload_vector; if (sendmsg (session->sock_fd, (const struct msghdr*)&session->message_header, 0) < 0) { - log_warn (LOG_NETLINK, "Failed to send netlink message. {}", strerror (errno)); + log_warn (LOG_NETLINK, std::format ("Failed to send netlink message. {}", strerror (errno))); return -1; } @@ -529,7 +529,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd abort_if_invalid_pointer_argument (last_ifaddr, "last_ifaddr"); size_t buf_size = static_cast(getpagesize ()); - log_debug (LOG_NETLINK, "receive buffer size == {}", buf_size); + log_debug (LOG_NETLINK, std::format ("receive buffer size == {}", buf_size)); size_t alloc_size = Helpers::multiply_with_overflow_check (sizeof(*response), buf_size); response = (unsigned char*)malloc (alloc_size); @@ -551,10 +551,10 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd netlink_reply.msg_iov = &reply_vector; length = recvmsg (session->sock_fd, &netlink_reply, 0); - log_debug (LOG_NETLINK, " length == {}", (int)length); + log_debug (LOG_NETLINK, std::format (" length == {}", (int)length)); if (length < 0) { - log_debug (LOG_NETLINK, "Failed to receive reply from netlink. {}", strerror (errno)); + log_debug (LOG_NETLINK, std::format ("Failed to receive reply from netlink. {}", strerror (errno))); goto cleanup; } @@ -582,7 +582,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; for (current_message = (struct nlmsghdr*)response; current_message && NLMSG_OK (current_message, static_cast(length)); current_message = NLMSG_NEXT (current_message, length)) { - log_debug (LOG_NETLINK, "next message... (type: {})", current_message->nlmsg_type); + log_debug (LOG_NETLINK, std::format ("next message... (type: {})", current_message->nlmsg_type)); switch (current_message->nlmsg_type) { /* See rtnetlink.h */ case RTM_NEWLINK: @@ -611,7 +611,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; default: - log_debug (LOG_NETLINK, " message type: {}", current_message->nlmsg_type); + log_debug (LOG_NETLINK, std::format (" message type: {}", current_message->nlmsg_type)); break; } } @@ -634,7 +634,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET: { struct sockaddr_in *sa4; if (rta_payload_length != 4) /* IPv4 address length */ { - log_warn (LOG_NETLINK, "Unexpected IPv4 address payload length {}", rta_payload_length); + log_warn (LOG_NETLINK, std::format ("Unexpected IPv4 address payload length {}", rta_payload_length)); return -1; } sa4 = (struct sockaddr_in*)calloc (1, sizeof (*sa4)); @@ -650,7 +650,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET6: { struct sockaddr_in6 *sa6; if (rta_payload_length != 16) /* IPv6 address length */ { - log_warn (LOG_NETLINK, "Unexpected IPv6 address payload length {}", rta_payload_length); + log_warn (LOG_NETLINK, std::format ("Unexpected IPv6 address payload length {}", rta_payload_length)); return -1; } sa6 = (struct sockaddr_in6*)calloc (1, sizeof (*sa6)); @@ -668,7 +668,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ default: { struct sockaddr *sagen; if (rta_payload_length > sizeof (sagen->sa_data)) { - log_warn (LOG_NETLINK, "Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data)); + log_warn (LOG_NETLINK, std::format ("Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data))); return -1; } @@ -701,9 +701,9 @@ fill_ll_address (struct sockaddr_ll_extended **sa, struct ifinfomsg *net_interfa /* The assert can only fail for Iniband links, which are quite unlikely to be found * in any mobile devices */ - log_debug (LOG_NETLINK, "rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type); + log_debug (LOG_NETLINK, std::format ("rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type)); if (static_cast(rta_payload_length) > sizeof ((*sa)->sll_addr)) { - log_info (LOG_NETLINK, "Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr)); + log_info (LOG_NETLINK, std::format ("Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr))); free (*sa); *sa = NULL; return -1; @@ -817,14 +817,14 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net memset (netmask_data, 0xFF, prefix_bytes); if (postfix_bytes > 0) memset (netmask_data + prefix_bytes + 1, 0x00, postfix_bytes); - log_debug (LOG_NETLINK, " calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length); + log_debug (LOG_NETLINK, std::format (" calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length)); 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 (Util::should_log (LOG_NETLINK)) { log_debug_nocheck (LOG_NETLINK, " netmask is: "sv); for (uint32_t i = 0; i < data_length; i++) { - log_debug_nocheck_fmt (LOG_NETLINK, "{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i]); + log_debug_nocheck (LOG_NETLINK, std::format ("{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i])); } } } @@ -847,7 +847,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if abort_if_invalid_pointer_argument (message, "message"); net_address = reinterpret_cast (NLMSG_DATA (message)); length = static_cast(IFA_PAYLOAD (message)); - log_debug (LOG_NETLINK, " address data length: {}", length); + log_debug (LOG_NETLINK, std::format (" address data length: {}", length)); if (length <= 0) { goto error; } @@ -864,7 +864,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " reading attributes"sv); while (RTA_OK (attribute, length)) { payload_size = RTA_PAYLOAD (attribute); - log_debug (LOG_NETLINK, " attribute payload_size == {}", payload_size); + log_debug (LOG_NETLINK, std::format (" attribute payload_size == {}", payload_size)); sa = NULL; switch (attribute->rta_type) { @@ -943,7 +943,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; default: - log_debug (LOG_NETLINK, " attribute type: {}", attribute->rta_type); + log_debug (LOG_NETLINK, std::format (" attribute type: {}", attribute->rta_type)); break; } @@ -962,7 +962,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " address has no name/label, getting one from interface"sv); ifa->ifa_name = name ? strdup (name) : NULL; } - log_debug (LOG_NETLINK, " address label: {}", optional_string (ifa->ifa_name)); + log_debug (LOG_NETLINK, std::format (" address label: {}", ifa->ifa_name)); if (calculate_address_netmask (ifa, net_address) < 0) { goto error; @@ -1016,13 +1016,13 @@ get_link_info (const struct nlmsghdr *message) goto error; } if (Util::should_log (LOG_NETLINK)) { - log_debug_nocheck_fmt (LOG_NETLINK, " interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); - log_debug_nocheck_fmt (LOG_NETLINK, " {}", optional_string (ifa->ifa_name)); + log_debug_nocheck (LOG_NETLINK, std::format (" interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name))); + log_debug_nocheck (LOG_NETLINK, std::format (" {}", ifa->ifa_name)); } break; case IFLA_BROADCAST: - log_debug (LOG_NETLINK, " interface broadcast ({} bytes)", RTA_PAYLOAD (attribute)); + log_debug (LOG_NETLINK, std::format (" interface broadcast ({} bytes)", RTA_PAYLOAD (attribute))); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1030,7 +1030,7 @@ get_link_info (const struct nlmsghdr *message) break; case IFLA_ADDRESS: - log_debug (LOG_NETLINK, " interface address ({} bytes)", RTA_PAYLOAD (attribute)); + log_debug (LOG_NETLINK, std::format (" interface address ({} bytes)", RTA_PAYLOAD (attribute))); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1047,7 +1047,7 @@ get_link_info (const struct nlmsghdr *message) attribute = RTA_NEXT (attribute, length); } - log_debug (LOG_NETLINK, "link flags: {:X}", ifa->ifa_flags); + log_debug (LOG_NETLINK, std::format ("link flags: {:X}", ifa->ifa_flags)); return ifa; error: @@ -1142,7 +1142,7 @@ print_ifla_name (int id) int i = 0; while (1) { if (iflas [i].value == -1 && iflas [i].name == 0) { - log_info_nocheck_fmt (LOG_NETLINK, "Unknown ifla->name: unknown id {}", id); + log_info_nocheck (LOG_NETLINK, std::format ("Unknown ifla->name: unknown id {}", id)); break; } @@ -1150,7 +1150,7 @@ print_ifla_name (int id) i++; continue; } - log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", optional_string (iflas [i].name), iflas [i].value); + log_info_nocheck (LOG_NETLINK, std::format ("ifla->name: {} ({})", iflas [i].name, iflas [i].value)); break; } } @@ -1165,7 +1165,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) char *msg, *tmp; if (!list) { - log_info_nocheck_fmt (LOG_NETLINK, "No list to print in {}", __FUNCTION__); + log_info_nocheck (LOG_NETLINK, std::format ("No list to print in {}", __FUNCTION__)); return; } @@ -1180,7 +1180,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) cur = cur->ifa_next; } - log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, optional_string (msg, "[no addresses]")); + log_info_nocheck (LOG_NETLINK, std::format ("{}: {}", title, msg ? msg : "[no addresses]"sv)); free (msg); } #endif diff --git a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh index 259a0d5c879..240223b396c 100644 --- a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh @@ -23,21 +23,21 @@ namespace xamarin::android { constexpr bool PREFER_AOT_CACHE = false; lib_handle = internal::MonodroidDl::monodroid_dlopen (library_name, MONO_DL_LOCAL, nullptr, PREFER_AOT_CACHE); if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", optional_string (library_name), optional_string (symbol_name)); + log_warn (LOG_ASSEMBLY, std::format ("Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name)); return nullptr; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", optional_string (library_name)); + log_debug (LOG_ASSEMBLY, std::format ("Library '{}' handle already cached by another thread", library_name)); } } } void *entry_handle = internal::MonodroidDl::monodroid_dlsym (lib_handle, symbol_name, nullptr, nullptr); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", optional_string (library_name), optional_string (symbol_name)); + log_warn (LOG_ASSEMBLY, std::format ("Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name)); return nullptr; } @@ -60,7 +60,7 @@ namespace xamarin::android { return nullptr; } - log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); + log_debug (LOG_ASSEMBLY, std::format ("Caching p/invoke entry {} @ {}", library_name, entrypoint_name)); (*api_map)[entrypoint_name] = entry_handle; return entry_handle; } @@ -81,7 +81,7 @@ namespace xamarin::android { ); if (already_loaded) { - log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); + log_debug (LOG_ASSEMBLY, std::format ("Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name)); } } @@ -147,7 +147,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", optional_string (library_name)); + log_warn (LOG_ASSEMBLY, std::format ("Internal error: null entry in p/invoke map for key '{}'", library_name)); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index 29ac736e433..269288a28c9 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -22,19 +22,18 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", - optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); + log_fatal (LOG_ASSEMBLY, std::format ("Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash)); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", optional_string (e.name), e.func, e.hash); + log_fatal (LOG_ASSEMBLY, std::format ("\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash)); } Helpers::abort_application ( LOG_ASSEMBLY, std::format ( "Failure handling a p/invoke request for '{}'@'{}'", - optional_string (entrypoint_name), - optional_string (library_name) + entrypoint_name, + library_name ) ); } @@ -77,8 +76,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha } // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below - log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", - optional_string (entrypoint_name), optional_string (library_name)); + log_debug (LOG_ASSEMBLY, std::format ("Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name)); } return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index 78d59b70bfa..d092be238cc 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -65,7 +65,7 @@ AndroidSystem::lookup_system_property (const char *name, size_t &value_len) noex return nullptr; if (application_config.system_property_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count); + log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count)); return nullptr; } @@ -138,7 +138,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 = Helpers::add_with_overflow_check (PROPERTY_VALUE_BUFFER_LEN, 1uz); - log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); + log_warn (LOG_DEFAULT, std::format ("Buffer to store system property may be too small, will copy only {} bytes", sp_value_len)); buf = new char [alloc_size]; } @@ -250,12 +250,12 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co } std::unique_ptr override_file {Util::path_combine (od, name)}; - log_info (LOG_DEFAULT, "Trying to get property from {}", override_file.get ()); + log_info (LOG_DEFAULT, std::format ("Trying to get property from {}", 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') { continue; } - log_info (LOG_DEFAULT, "Property '{}' from {} has value '{}'.", name, od, *value); + log_info (LOG_DEFAULT, std::format ("Property '{}' from {} has value '{}'.", name, od, *value)); return result; } #endif // def DEBUG @@ -281,7 +281,7 @@ AndroidSystem::create_update_dir (char *override_dir) noexcept override_dirs [0] = override_dir; Util::create_public_directory (override_dir); - log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); + log_warn (LOG_DEFAULT, std::format ("Creating public update directory: `{}`", override_dir)); } bool @@ -306,16 +306,16 @@ AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exis if (path == nullptr || *path == '\0') return nullptr; - log_info (LOG_ASSEMBLY, "Trying to load shared library '{}'", path); + log_info (LOG_ASSEMBLY, std::format ("Trying to load shared library '{}'", path)); if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { - log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); + log_info (LOG_ASSEMBLY, std::format ("Shared library '{}' not found", path)); return nullptr; } char *error = nullptr; void *handle = java_interop_lib_load (path, dl_flags, &error); if (handle == nullptr && Util::should_log (LOG_ASSEMBLY)) - log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '{}'. {}", path, error); + log_info_nocheck (LOG_ASSEMBLY, std::format ("Failed to load shared library '{}'. {}", path, error)); java_interop_free (error); return handle; } @@ -450,9 +450,9 @@ AndroidSystem::get_max_gref_count_from_system (void) noexcept if (max < 0) max = std::numeric_limits::max (); if (*e) { - log_warn (LOG_GC, "Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); + log_warn (LOG_GC, std::format ("Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ())); } - log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); + log_warn (LOG_GC, std::format ("Overriding max JNI Global Reference count to {}", max)); } return max; } @@ -478,7 +478,7 @@ AndroidSystem::setup_environment (const char *name, const char *value) noexcept if (isupper (name [0]) || name [0] == '_') { if (setenv (name, v, 1) < 0) - log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("(Debug) Failed to set environment variable: {}", strerror (errno))); return; } @@ -492,13 +492,13 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept struct stat sbuf; if (::stat (path, &sbuf) < 0) { - log_warn (LOG_DEFAULT, "Failed to stat the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to stat the environment override file {}: {}", path, strerror (errno))); return; } int fd = open (path, O_RDONLY); if (fd < 0) { - log_warn (LOG_DEFAULT, "Failed to open the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to open the environment override file {}: {}", path, strerror (errno))); return; } @@ -515,7 +515,7 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept } while (r < 0 && errno == EINTR); if (nread == 0) { - log_warn (LOG_DEFAULT, "Failed to read the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to read the environment override file {}: {}", path, strerror (errno))); return; } @@ -536,26 +536,26 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept // # Variable value, terminated with NUL and padded to [value width] with NUL characters // value\0 if (nread < OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) { - log_warn (LOG_DEFAULT, "Invalid format of the environment override file {}: malformatted header", path); + log_warn (LOG_DEFAULT, std::format ("Invalid format of the environment override file {}: malformatted header", path)); return; } char *endptr; unsigned long name_width = strtoul (buf.get (), &endptr, 16); if ((name_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path); + log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: name width has invalid format", path)); return; } unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path); + log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: value width has invalid format", path)); return; } uint64_t data_width = name_width + value_width; if (data_width > file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path); + log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: invalid data size", path)); return; } @@ -563,11 +563,11 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept char *name = buf.get () + OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE; while (data_size > 0 && data_size >= data_width) { if (*name == '\0') { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ()); + log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ())); return; } - log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width); + log_debug (LOG_DEFAULT, std::format ("Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width)); setup_environment (name, name + name_width); name += data_width; data_size -= data_width; @@ -602,10 +602,10 @@ AndroidSystem::setup_environment () noexcept } if (aotMode != MonoAotMode::MONO_AOT_MODE_LAST) { - log_debug (LOG_DEFAULT, "Mono AOT mode: {}", mono_aot_mode_name); + log_debug (LOG_DEFAULT, std::format ("Mono AOT mode: {}", mono_aot_mode_name)); } else { if (!is_interpreter_enabled ()) { - log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: {}", mono_aot_mode_name); + log_warn (LOG_DEFAULT, std::format ("Unknown Mono AOT mode: {}", mono_aot_mode_name)); } else { log_warn (LOG_DEFAULT, "Mono AOT mode: interpreter"sv); } @@ -613,7 +613,7 @@ AndroidSystem::setup_environment () noexcept } if (application_config.environment_variable_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count); + log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count)); return; } @@ -629,10 +629,10 @@ AndroidSystem::setup_environment () noexcept var_value = ""; #if defined (DEBUG) - log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); + log_info (LOG_DEFAULT, std::format ("Setting environment variable '{}' to '{}'", var_name, var_value)); #endif // def DEBUG if (setenv (var_name, var_value, 1) < 0) - log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to set environment variable: {}", strerror (errno))); } #if defined (DEBUG) log_debug (LOG_DEFAULT, "Loading environment from override directories."sv); @@ -641,9 +641,9 @@ AndroidSystem::setup_environment () noexcept continue; } std::unique_ptr env_override_file {Util::path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; - log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); + log_debug (LOG_DEFAULT, std::format ("{}", env_override_file.get ())); if (Util::file_exists (env_override_file.get ())) { - log_debug (LOG_DEFAULT, "Loading {}", env_override_file.get ()); + log_debug (LOG_DEFAULT, std::format ("Loading {}", env_override_file.get ())); setup_environment_from_override_file (env_override_file.get ()); } } @@ -671,12 +671,12 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep { // 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 {}", libmonodroid_path.get ()); + log_debug (LOG_ASSEMBLY, std::format ("Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ())); if (!Util::file_exists (libmonodroid_path.get ())) { - log_debug (LOG_ASSEMBLY, "{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); + log_debug (LOG_ASSEMBLY, std::format ("{} 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 {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, std::format ("Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); set_embedded_dso_mode_enabled (false); } } @@ -689,7 +689,7 @@ AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks 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: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, std::format ("Added filesystem DSO lookup location: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); } else { log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); @@ -725,7 +725,7 @@ AndroidSystem::add_apk_libdir (const char *apk, size_t &index, const char *abi) { 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: {}", app_lib_directories[index]); + log_debug (LOG_ASSEMBLY, std::format ("Added APK DSO lookup location: {}", app_lib_directories[index])); index++; } diff --git a/src/native/mono/runtime-base/monodroid-dl.hh b/src/native/mono/runtime-base/monodroid-dl.hh index 93cb8b70b48..621d0744fe7 100644 --- a/src/native/mono/runtime-base/monodroid-dl.hh +++ b/src/native/mono/runtime-base/monodroid-dl.hh @@ -48,11 +48,11 @@ namespace xamarin::android::internal size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); + log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in AOT cache", hash)); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); + log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in DSO cache", hash)); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } @@ -102,7 +102,7 @@ namespace xamarin::android::internal if (MonodroidState::is_startup_in_progress ()) { auto ignore_component = [&](const char *label, MonoComponent component) -> bool { if ((application_config.mono_components_mask & component) != component) { - log_info (LOG_ASSEMBLY, "Mono '{}' component requested but not packaged, ignoring", label); + log_info (LOG_ASSEMBLY, std::format ("Mono '{}' component requested but not packaged, ignoring", label)); return true; } @@ -150,7 +150,7 @@ namespace xamarin::android::internal } hash_t name_hash = xxhash::hash (name, strlen (name)); - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash); + log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash)); DSOCacheEntry *dso = nullptr; if (prefer_aot_cache) { @@ -167,7 +167,7 @@ namespace xamarin::android::internal dso = find_only_dso_cache_entry (name_hash); } - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name); + log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name)); if (dso == nullptr) { // DSO not known at build time, try to load it @@ -177,7 +177,7 @@ namespace xamarin::android::internal } if (dso->ignore) { - log_info (LOG_ASSEMBLY, "Request to load '{}' ignored, it is known not to exist", dso->name); + log_info (LOG_ASSEMBLY, std::format ("Request to load '{}' ignored, it is known not to exist", dso->name)); return nullptr; } From 8e0aae54e0696987a162b1270f87fa6329175e1b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 27 Nov 2024 20:51:12 +0100 Subject: [PATCH 046/143] More std::format --- .../include/runtime-base/strings.hh | 8 ++-- src/native-clr/include/shared/log_level.hh | 1 - .../mono/monodroid/embedded-assemblies-zip.cc | 2 +- .../mono/monodroid/mono-image-loader.hh | 2 +- .../mono/monodroid/monodroid-glue-internal.hh | 2 +- .../mono/monodroid/monodroid-networkinfo.cc | 6 +-- .../mono/monodroid/monodroid-tracing.cc | 2 +- .../monodroid/xamarin-android-app-context.cc | 38 ++++++++++--------- .../mono/pinvoke-override/precompiled.cc | 3 +- .../mono/runtime-base/internal-pinvokes.hh | 1 + src/native/mono/runtime-base/logger.cc | 18 +++++---- .../mono/runtime-base/timing-internal.cc | 6 +-- .../mono/runtime-base/timing-internal.hh | 4 +- src/native/mono/runtime-base/timing.hh | 4 +- src/native/mono/runtime-base/util.cc | 8 ++-- src/native/mono/runtime-base/util.hh | 4 +- src/native/mono/shared/cpp-util.hh | 2 +- src/native/mono/shared/helpers.cc | 13 ++++--- src/native/mono/shared/log_functions.cc | 4 +- .../debug-app-helper.cc | 34 ++++++++--------- 20 files changed, 84 insertions(+), 78 deletions(-) diff --git a/src/native-clr/include/runtime-base/strings.hh b/src/native-clr/include/runtime-base/strings.hh index aae49968f84..6537b360aad 100644 --- a/src/native-clr/include/runtime-base/strings.hh +++ b/src/native-clr/include/runtime-base/strings.hh @@ -197,7 +197,7 @@ namespace xamarin::android { } if (!can_access (start_index)) { - log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); + log_error (LOG_DEFAULT, std::format ("Cannot convert string to integer, index {} is out of range", start_index)); return false; } @@ -221,17 +221,17 @@ namespace xamarin::android { } if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); + log_error (LOG_DEFAULT, std::format ("Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max))); return false; } if (endp == s) { - log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); + log_error (LOG_DEFAULT, std::format ("Value {} does not represent a base {} integer", reinterpret_cast(s), base)); return false; } if (*endp != '\0') { - log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); + log_error (LOG_DEFAULT, std::format ("Value {} has non-numeric characters at the end", reinterpret_cast(s))); return false; } diff --git a/src/native-clr/include/shared/log_level.hh b/src/native-clr/include/shared/log_level.hh index e11dc18dae9..31a1b22dac0 100644 --- a/src/native-clr/include/shared/log_level.hh +++ b/src/native-clr/include/shared/log_level.hh @@ -126,4 +126,3 @@ static inline constexpr void log_fatal (LogCategories category, std::string_view } extern unsigned int log_categories; -#endif // ndef LOG_LEVEL_HH diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 59069330dfb..d195b26fcaf 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -45,7 +45,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vectorCallStaticObjectMethod (NetworkInterface_class, NetworkInterface_getByName, NetworkInterface_nameArg); env->DeleteLocalRef (NetworkInterface_nameArg); if (env->ExceptionOccurred ()) { - log_warn (LOG_NET, "Java exception occurred while looking up the interface '{}'", ifname); + log_warn (LOG_NET, std::format ("Java exception occurred while looking up the interface '{}'", ifname)); env->ExceptionDescribe (); env->ExceptionClear (); goto leave; } if (!networkInterface) { - log_warn (LOG_NET, "Failed to look up interface '{}' using Java API", ifname); + log_warn (LOG_NET, std::format ("Failed to look up interface '{}' using Java API", ifname)); ret = FALSE; goto leave; } @@ -118,7 +118,7 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo leave: if (!ret) - log_warn (LOG_NET, "Unable to determine interface '{}' state using Java API", ifname); + log_warn (LOG_NET, std::format ("Unable to determine interface '{}' state using Java API", ifname)); if (networkInterface != nullptr && env != nullptr) { env->DeleteLocalRef (networkInterface); diff --git a/src/native/mono/monodroid/monodroid-tracing.cc b/src/native/mono/monodroid/monodroid-tracing.cc index adb9f0db1d6..892a5938393 100644 --- a/src/native/mono/monodroid/monodroid-tracing.cc +++ b/src/native/mono/monodroid/monodroid-tracing.cc @@ -27,7 +27,7 @@ MonodroidRuntime::log_traces (JNIEnv *env, TraceKind kind, const char *first_lin char *err = nullptr; void *handle = MonodroidDl::monodroid_dlopen (SharedConstants::xamarin_native_tracing_name.data (), MONO_DL_EAGER, &err, nullptr); if (handle == nullptr) { - log_warn (LOG_DEFAULT, "Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err); + log_warn (LOG_DEFAULT, std::format ("Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err)); } else { load_symbol (handle, "xa_get_native_backtrace", _xa_get_native_backtrace); load_symbol (handle, "xa_get_managed_backtrace", _xa_get_managed_backtrace); diff --git a/src/native/mono/monodroid/xamarin-android-app-context.cc b/src/native/mono/monodroid/xamarin-android-app-context.cc index 9ef193ddeb7..e55635f2443 100644 --- a/src/native/mono/monodroid/xamarin-android-app-context.cc +++ b/src/native/mono/monodroid/xamarin-android-app-context.cc @@ -15,7 +15,7 @@ MonodroidRuntime::get_method_name (uint32_t mono_image_index, uint32_t method_to { uint64_t id = (static_cast(mono_image_index) << 32) | method_token; - log_debug (LOG_ASSEMBLY, "MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index); + log_debug (LOG_ASSEMBLY, std::format ("MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index)); size_t i = 0uz; while (mm_method_names[i].id != 0) { if (mm_method_names[i].id == id) { @@ -43,9 +43,10 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas { log_debug ( LOG_ASSEMBLY, - "MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", - optional_string (get_method_name (mono_image_index, method_token)), method_token, - optional_string (get_class_name (class_index)), class_index + std::format ("MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", + get_method_name (mono_image_index, method_token), method_token, + get_class_name (class_index), class_index + ) ); if (class_index >= marshal_methods_number_of_classes) [[unlikely]] { @@ -80,29 +81,32 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, - "Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", - optional_string (mono_method_full_name (method, true)), - ret, - mono_image_index, - class_index, - method_token + std::format ("Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", + mono_method_full_name (method, true), + ret, + mono_image_index, + class_index, + method_token + ) ); return; } log_fatal ( LOG_DEFAULT, - "Failed to obtain function pointer to method '{}' in class '{}'", - optional_string (get_method_name (mono_image_index, method_token)), - optional_string (get_class_name (class_index)) + std::format ("Failed to obtain function pointer to method '{}' in class '{}'", + get_method_name (mono_image_index, method_token), + get_class_name (class_index) + ) ); log_fatal ( LOG_DEFAULT, - "Looked for image index {}, class index {}, method token {:x}", - mono_image_index, - class_index, - method_token + std::format ("Looked for image index {}, class index {}, method token {:x}", + mono_image_index, + class_index, + method_token + ) ); if (image == nullptr) { diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index 269288a28c9..1ef4bbfaba0 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -67,8 +67,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", - optional_string (entrypoint_name), optional_string (library_name)); + log_fatal (LOG_ASSEMBLY, std::format ("Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name)); return nullptr; // let Mono deal with the fallout } diff --git a/src/native/mono/runtime-base/internal-pinvokes.hh b/src/native/mono/runtime-base/internal-pinvokes.hh index 200c7b97204..1fbfc4c1e01 100644 --- a/src/native/mono/runtime-base/internal-pinvokes.hh +++ b/src/native/mono/runtime-base/internal-pinvokes.hh @@ -3,6 +3,7 @@ #include #include +//#include #include #include diff --git a/src/native/mono/runtime-base/logger.cc b/src/native/mono/runtime-base/logger.cc index 92c3137cd7a..de5f6dee5cf 100644 --- a/src/native/mono/runtime-base/logger.cc +++ b/src/native/mono/runtime-base/logger.cc @@ -29,11 +29,13 @@ namespace { if (path && access (path, W_OK) < 0) { log_warn (category, - "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", - optional_string (path), - strerror (errno), - optional_string (override_dir), - optional_string (filename) + std::format ( + "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", + path, + strerror (errno), + override_dir, + filename + ) ); path = NULL; } @@ -51,7 +53,7 @@ namespace { if (f) { Util::set_world_accessable (path); } else { - log_warn (category, "Could not open path '{}' for logging: {}", optional_string (path), strerror (errno)); + log_warn (category, std::format ("Could not open path '{}' for logging: {}", path, strerror (errno))); } free (p); @@ -77,12 +79,12 @@ Logger::set_debugger_log_level (const char *level) noexcept unsigned long v = strtoul (level, nullptr, 0); if (v == std::numeric_limits::max () && errno == ERANGE) { - log_error (LOG_DEFAULT, "Invalid debugger log level value '{}', expecting a positive integer or zero", level); + log_error (LOG_DEFAULT, std::format ("Invalid debugger log level value '{}', 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 {}, resetting to the maximum value.", std::numeric_limits::max ()); + log_warn (LOG_DEFAULT, std::format ("Debugger log level value is higher than the maximum of {}, resetting to the maximum value.", std::numeric_limits::max ())); v = std::numeric_limits::max (); } diff --git a/src/native/mono/runtime-base/timing-internal.cc b/src/native/mono/runtime-base/timing-internal.cc index 6efcfdae461..7b23705d880 100644 --- a/src/native/mono/runtime-base/timing-internal.cc +++ b/src/native/mono/runtime-base/timing-internal.cc @@ -78,11 +78,11 @@ FastTiming::dump () noexcept log_write (LOG_TIMING, LogLevel::Info, "[2/4] Accumulated performance results"); ns_to_time (total_assembly_load_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/5] Assembly load: {}:{}::{}", sec, ms, ns); + log_info_nocheck (LOG_TIMING, std::format (" [2/5] Assembly load: {}:{}::{}", sec, ms, ns)); ns_to_time (total_java_to_managed_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns); + log_info_nocheck (LOG_TIMING, std::format (" [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns)); ns_to_time (total_managed_to_java_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns); + log_info_nocheck (LOG_TIMING, std::format (" [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns)); } diff --git a/src/native/mono/runtime-base/timing-internal.hh b/src/native/mono/runtime-base/timing-internal.hh index 6389e719e7e..804e2544a9d 100644 --- a/src/native/mono/runtime-base/timing-internal.hh +++ b/src/native/mono/runtime-base/timing-internal.hh @@ -144,7 +144,7 @@ namespace xamarin::android::internal // likely we'll run out of memory way, way, way before that happens size_t old_size = events.capacity (); events.reserve (old_size << 1); - log_warn (LOG_TIMING, "Reallocated timing event buffer from {} to {}", old_size, events.size ()); + log_warn (LOG_TIMING, std::format ("Reallocated timing event buffer from {} to {}", old_size, events.size ())); } } @@ -246,7 +246,7 @@ namespace xamarin::android::internal [[gnu::always_inline]] bool is_valid_event_index (size_t index, const char *method_name) noexcept { if (index >= events.capacity ()) [[unlikely]] { - log_warn (LOG_TIMING, "Invalid event index passed to method '{}'", method_name); + log_warn (LOG_TIMING, std::format ("Invalid event index passed to method '{}'", method_name)); return false; } diff --git a/src/native/mono/runtime-base/timing.hh b/src/native/mono/runtime-base/timing.hh index 191ec55df2f..31f9892e918 100644 --- a/src/native/mono/runtime-base/timing.hh +++ b/src/native/mono/runtime-base/timing.hh @@ -93,14 +93,14 @@ namespace xamarin::android { timing_diff diff (period); - log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); + log_info_nocheck (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); } static void warn (timing_period const &period, const char *message) noexcept { timing_diff diff (period); - log_warn (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); + log_warn (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); } managed_timing_sequence* get_available_sequence () noexcept diff --git a/src/native/mono/runtime-base/util.cc b/src/native/mono/runtime-base/util.cc index d377cc46c31..388c9beb9c3 100644 --- a/src/native/mono/runtime-base/util.cc +++ b/src/native/mono/runtime-base/util.cc @@ -150,7 +150,7 @@ Util::create_public_directory (const char *dir) mode_t m = umask (0); int ret = mkdir (dir, 0777); if (ret < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", dir, std::strerror (errno))); } umask (m); } @@ -198,7 +198,7 @@ Util::set_world_accessable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); + log_error (LOG_DEFAULT, std::format ("chmod(\"{}\", 0664) failed: {}", path, strerror (errno))); } } @@ -211,7 +211,7 @@ Util::set_user_executable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\") failed: {}", path, strerror (errno)); + log_error (LOG_DEFAULT, std::format ("chmod(\"{}\") failed: {}", path, strerror (errno))); } } @@ -298,7 +298,7 @@ Util::monodroid_fopen (const char *filename, const char *mode) */ ret = fopen (filename, mode); if (ret == nullptr) { - log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); + log_error (LOG_DEFAULT, std::format ("fopen failed for file {}: {}", filename, strerror (errno))); return nullptr; } diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 3dbdeae10bc..2c553ff63a6 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -80,7 +80,7 @@ namespace xamarin::android { struct stat sbuf; if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, "Failed to stat file '{}': {}", file_name, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, std::format ("Failed to stat file '{}': {}", file_name, std::strerror (errno))); return std::nullopt; } @@ -91,7 +91,7 @@ namespace xamarin::android { int fd = openat (dirfd, file_name, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, "Failed to open file '{}' for reading: {}", file_name, std::strerror (errno)); + log_error (LOG_ASSEMBLY, std::format ("Failed to open file '{}' for reading: {}", file_name, std::strerror (errno))); return std::nullopt; } diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index f2f03b9d5b6..1c0e5cfd30e 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -86,7 +86,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l // 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: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); + log_info_nocheck (LOG_DEFAULT, std::format ("loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ())); } namespace xamarin::android diff --git a/src/native/mono/shared/helpers.cc b/src/native/mono/shared/helpers.cc index 9638b16ebd5..645f30e0d84 100644 --- a/src/native/mono/shared/helpers.cc +++ b/src/native/mono/shared/helpers.cc @@ -11,7 +11,7 @@ using namespace xamarin::android; Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept { // Log it, but also... - log_fatal (category, "{}", message); + log_fatal (category, std::string_view { message }); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -35,11 +35,12 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - "Abort at {}:{}:{} ('%s')", - file_name, - sloc.line (), - sloc.column (), - sloc.function_name () + std::format ("Abort at {}:{}:{} ('%s')", + file_name, + sloc.line (), + sloc.column (), + sloc.function_name () + ) ); } std::abort (); diff --git a/src/native/mono/shared/log_functions.cc b/src/native/mono/shared/log_functions.cc index c6d61f54d0d..e82f2bd5856 100644 --- a/src/native/mono/shared/log_functions.cc +++ b/src/native/mono/shared/log_functions.cc @@ -3,8 +3,8 @@ #include -#include "java-interop-logger.h" -#include "log_level.hh" +//#include "java-interop-logger.h" +#include "log_types.hh" // Must match the same ordering as LogCategories static constexpr std::array log_names = { diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index e64c42750c8..711317c7a08 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -48,7 +48,7 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); + log_warn (LOG_DEFAULT, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); } const char *monosgen_path = get_libmonosgen_path (); @@ -74,10 +74,10 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) break; log_warn (LOG_DEFAULT, - "Copying file `{}` from external location `{}` to internal location `{}`", - optional_string (file), - optional_string (from_dir), - optional_string (to_dir) + std::format ( + "Copying file `{}` from external location `{}` to internal location `{}`", + file, from_dir, to_dir + ) ); to_file = Util::path_combine (to_dir, file); @@ -86,12 +86,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) int r = unlink (to_file); if (r < 0 && errno != ENOENT) { - log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", optional_string (to_file), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Unable to delete file `{}`: {}", to_file, strerror (errno))); break; } if (!Util::file_copy (to_file, from_file)) { - log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", optional_string (from_file), optional_string (to_file), strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno))); break; } @@ -110,22 +110,22 @@ copy_native_libraries_to_internal_location () dirent *e; char *dir_path = Util::path_combine (od, "lib"); - log_warn (LOG_DEFAULT, "checking directory: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, std::format ("checking directory: `{}`", dir_path)); if (dir_path == nullptr || !Util::directory_exists (dir_path)) { - log_warn (LOG_DEFAULT, "directory does not exist: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, std::format ("directory does not exist: `{}`", dir_path)); delete[] dir_path; continue; } if ((dir = ::opendir (dir_path)) == nullptr) { - log_warn (LOG_DEFAULT, "could not open directory: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, std::format ("could not open directory: `{}`", dir_path)); delete[] dir_path; continue; } while ((e = readdir (dir)) != nullptr) { - log_warn (LOG_DEFAULT, "checking file: `{}`", optional_string (e->d_name)); + log_warn (LOG_DEFAULT, std::format ("checking file: `{}`", 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); } @@ -142,9 +142,9 @@ runtime_exists (const char *dir, char*& libmonoso) return false; libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); - log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", optional_string (libmonoso)); + log_warn (LOG_DEFAULT, std::format ("Checking whether Mono runtime exists at: {}", libmonoso)); if (Util::file_exists (libmonoso)) { - log_info (LOG_DEFAULT, "Mono runtime found at: {}", optional_string (libmonoso)); + log_info (LOG_DEFAULT, std::format ("Mono runtime found at: {}", libmonoso)); return true; } delete[] libmonoso; @@ -196,25 +196,25 @@ get_libmonosgen_path () if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { - log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", optional_string (link), optional_string (libmonoso)); + log_warn (LOG_DEFAULT, std::format ("symlink exists, recreating: {} -> {}", link, libmonoso)); unlink (link); result = symlink (libmonoso, link); } if (result != 0) - log_warn (LOG_DEFAULT, "symlink failed with errno={} {}", errno, strerror (errno)); + log_warn (LOG_DEFAULT, std::format ("symlink failed with errno={} {}", errno, strerror (errno))); } delete[] libmonoso; libmonoso = link; } - log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", optional_string (libmonoso)); + log_warn (LOG_DEFAULT, std::format ("Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv)); if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; if (runtime_exists (AndroidSystem::SYSTEM_LIB_PATH.data (), libmonoso)) return libmonoso; - log_fatal (LOG_DEFAULT, "Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO); + log_fatal (LOG_DEFAULT, std::format ("Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO)); for (const char *od : AndroidSystem::override_dirs) { if (od == nullptr) From bb9fcffe3cfaee4580592dae8d158ffe2f052983 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 28 Nov 2024 17:17:26 +0100 Subject: [PATCH 047/143] Friendlier, no need to use `std::format` directly in log_* anymore --- .../include/runtime-base/strings.hh | 8 +- src/native-clr/include/shared/log_level.hh | 94 ++++------ src/native/mono/monodroid/debug.cc | 61 +++---- .../mono/monodroid/embedded-assemblies-zip.cc | 69 ++++--- .../mono/monodroid/embedded-assemblies.cc | 171 +++++++++--------- .../mono/monodroid/embedded-assemblies.hh | 6 +- .../mono/monodroid/monodroid-glue-internal.hh | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 71 ++++---- .../mono/monodroid/monodroid-networkinfo.cc | 6 +- .../mono/monodroid/monodroid-tracing.cc | 2 +- src/native/mono/monodroid/osbridge.cc | 160 ++++++++-------- .../monodroid/xamarin-android-app-context.cc | 38 ++-- .../mono/monodroid/xamarin_getifaddrs.cc | 56 +++--- .../pinvoke-override-api-impl.hh | 12 +- .../mono/pinvoke-override/precompiled.cc | 8 +- .../mono/runtime-base/android-system.cc | 64 +++---- src/native/mono/runtime-base/monodroid-dl.hh | 12 +- .../mono/runtime-base/timing-internal.cc | 6 +- .../mono/runtime-base/timing-internal.hh | 4 +- src/native/mono/runtime-base/timing.hh | 4 +- src/native/mono/runtime-base/util.cc | 8 +- src/native/mono/runtime-base/util.hh | 4 +- src/native/mono/shared/cpp-util.hh | 2 +- src/native/mono/shared/helpers.cc | 13 +- src/native/mono/shared/log_functions.cc | 4 +- .../debug-app-helper.cc | 32 ++-- 26 files changed, 431 insertions(+), 486 deletions(-) diff --git a/src/native-clr/include/runtime-base/strings.hh b/src/native-clr/include/runtime-base/strings.hh index 6537b360aad..aae49968f84 100644 --- a/src/native-clr/include/runtime-base/strings.hh +++ b/src/native-clr/include/runtime-base/strings.hh @@ -197,7 +197,7 @@ namespace xamarin::android { } if (!can_access (start_index)) { - log_error (LOG_DEFAULT, std::format ("Cannot convert string to integer, index {} is out of range", start_index)); + log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); return false; } @@ -221,17 +221,17 @@ namespace xamarin::android { } if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, std::format ("Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max))); + log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); return false; } if (endp == s) { - log_error (LOG_DEFAULT, std::format ("Value {} does not represent a base {} integer", reinterpret_cast(s), base)); + log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); return false; } if (*endp != '\0') { - log_error (LOG_DEFAULT, std::format ("Value {} has non-numeric characters at the end", reinterpret_cast(s))); + log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); return false; } diff --git a/src/native-clr/include/shared/log_level.hh b/src/native-clr/include/shared/log_level.hh index 31a1b22dac0..66b1cae5097 100644 --- a/src/native-clr/include/shared/log_level.hh +++ b/src/native-clr/include/shared/log_level.hh @@ -6,6 +6,7 @@ #include #include "java-interop-logger.h" +#include "log_level.hh" // We redeclare macros here #if defined(log_debug) @@ -16,59 +17,42 @@ #undef log_info #endif -#define DO_LOG_FMT(_level, _category_, _message_) \ +#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ do { \ if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck ((_category_), _message_); \ + ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ } \ } while (0) -#define log_debug(_category_, _message_) DO_LOG_FMT (debug, (_category_), (_message_)) -#define log_info(_category_, _message_) DO_LOG_FMT (info, (_category_), (_message_)) +// +// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec +// -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 - }; +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +namespace xamarin::android { // 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; } -// -// This will be enabled once all log_* calls are converted to std::format format -// -// template [[gnu::always_inline]] -// static inline constexpr void log_debug (LogCategories category, std::format_string fmt, Args&& ...args) -// { -// if (detail::_category_is_enabled (category)) { - -// log_debug_nocheck (category, std::format (fmt, std::forward(args)...).c_str ()); -// } -// } - -[[gnu::always_inline]] -static inline constexpr void log_debug_nocheck (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) { - log_write (category, xamarin::android::LogLevel::Debug, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] @@ -77,10 +61,10 @@ static inline constexpr void log_debug_nocheck (LogCategories category, std::str log_write (category, xamarin::android::LogLevel::Debug, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_info_nocheck (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) { - log_write (category, xamarin::android::LogLevel::Info, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] @@ -89,38 +73,38 @@ static inline constexpr void log_info_nocheck (LogCategories category, std::stri log_write (category, xamarin::android::LogLevel::Info, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_warn (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept { - log_write (category, xamarin::android::LogLevel::Warn, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] -static inline constexpr void log_warn (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept { log_write (category, xamarin::android::LogLevel::Warn, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_error (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept { - log_write (category, xamarin::android::LogLevel::Error, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] -static inline constexpr void log_error (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept { log_write (category, xamarin::android::LogLevel::Error, message.data ()); } -[[gnu::always_inline]] -static inline constexpr void log_fatal (LogCategories category, std::string const& message) noexcept +template [[gnu::always_inline]] +static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept { - log_write (category, xamarin::android::LogLevel::Fatal, message.c_str ()); + log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); } [[gnu::always_inline]] -static inline constexpr void log_fatal (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept { log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); } diff --git a/src/native/mono/monodroid/debug.cc b/src/native/mono/monodroid/debug.cc index 18d355bfa84..e72b7aa19a6 100644 --- a/src/native/mono/monodroid/debug.cc +++ b/src/native/mono/monodroid/debug.cc @@ -95,10 +95,9 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (!found) log_warn (LOG_DEFAULT, - std::format ("The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", - mname.get (), - libname.get () - ) + "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", + mname.get (), + libname.get () ); } @@ -110,7 +109,7 @@ bool Debug::load_profiler (void *handle, const char *desc, const char *symbol) { ProfilerInitializer func = reinterpret_cast (java_interop_lib_symbol (handle, symbol, nullptr)); - log_warn (LOG_DEFAULT, std::format ("Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func))); + log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func)); if (func != nullptr) { func (desc); @@ -140,7 +139,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, std::format ("Connection options: '{}'", options)); + log_info (LOG_DEFAULT, "Connection options: '{}'", options); args = Util::monodroid_strsplit (options, ",", 0); @@ -150,12 +149,12 @@ Debug::parse_options (char *options, ConnOptions *opts) if (strstr (arg, "port=") == arg) { int port = atoi (arg + strlen ("port=")); if (port < 0 || port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, std::format ("Invalid debug port value {}", port)); + log_error (LOG_DEFAULT, "Invalid debug port value {}", port); continue; } conn_port = static_cast(port); - log_info (LOG_DEFAULT, std::format ("XS port = {}", conn_port)); + log_info (LOG_DEFAULT, "XS port = {}", conn_port); } else if (strstr (arg, "timeout=") == arg) { char *endp; @@ -164,7 +163,7 @@ Debug::parse_options (char *options, ConnOptions *opts) if ((endp == arg) || (*endp != '\0')) log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, std::format ("Unknown connection option: '{}'", arg)); + log_info (LOG_DEFAULT, "Unknown connection option: '{}'", arg); } } } @@ -188,7 +187,7 @@ Debug::start_connection (char *options) cur_time = time (nullptr); if (opts.timeout_time && cur_time > opts.timeout_time) { - log_warn (LOG_DEBUGGER, std::format ("Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time)); + log_warn (LOG_DEBUGGER, "Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time); return DebuggerConnectionStatus::Unconnected; } @@ -199,7 +198,7 @@ Debug::start_connection (char *options) res = pthread_create (&conn_thread_id, nullptr, xamarin::android::conn_thread, this); if (res) { - log_error (LOG_DEFAULT, std::format ("Failed to create connection thread: {}", strerror (errno))); + log_error (LOG_DEFAULT, "Failed to create connection thread: {}", strerror (errno)); return DebuggerConnectionStatus::Error; } @@ -263,20 +262,20 @@ Debug::process_connection (int fd) return false; } if (rv <= 0) { - log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); + log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); return false; } rv = Util::recv_uninterrupted (fd, command, cmd_len); if (rv <= 0) { - log_info (LOG_DEFAULT, std::format ("Error while receiving command from XS ({})", strerror (errno))); + log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); return false; } // null-terminate command [cmd_len] = 0; - log_info (LOG_DEFAULT, std::format ("Received cmd: '{}'.", command)); + log_info (LOG_DEFAULT, "Received cmd: '{}'.", command); if (process_cmd (fd, command)) return true; @@ -288,14 +287,14 @@ Debug::handle_server_connection (void) { int listen_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_socket == -1) { - log_info (LOG_DEFAULT, std::format ("Could not create socket for XS to connect to: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Could not create socket for XS to connect to: {}", strerror (errno)); return 1; } int flags = 1; int rv = setsockopt (listen_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); if (rv == -1 && Util::should_log (LOG_DEFAULT)) { - log_info_nocheck (LOG_DEFAULT, std::format ("Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno))); + log_info_nocheck_fmt (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno)); // not a fatal failure } @@ -309,7 +308,7 @@ Debug::handle_server_connection (void) listen_addr.sin_addr.s_addr = INADDR_ANY; rv = bind (listen_socket, (struct sockaddr *) &listen_addr, sizeof (listen_addr)); if (rv == -1) { - log_info (LOG_DEFAULT, std::format ("Could not bind to address: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Could not bind to address: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -321,7 +320,7 @@ Debug::handle_server_connection (void) rv = listen (listen_socket, 1); if (rv == -1) { - log_info (LOG_DEFAULT, std::format ("Could not listen for XS: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Could not listen for XS: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -371,7 +370,7 @@ Debug::handle_server_connection (void) } while (rv == -1 && errno == EINTR); if (rv == -1) { - log_info (LOG_DEFAULT, std::format ("Failed while waiting for XS to connect: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -379,18 +378,18 @@ Debug::handle_server_connection (void) socklen_t len = sizeof (struct sockaddr_in); int fd = accept (listen_socket, (struct sockaddr *) &listen_addr, &len); if (fd == -1) { - log_info (LOG_DEFAULT, std::format ("Failed to accept connection from XS: {}", strerror (errno))); + log_info (LOG_DEFAULT, "Failed to accept connection from XS: {}", strerror (errno)); rv = 3; goto cleanup; } flags = 1; if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flags, sizeof (flags)) < 0) { - log_info (LOG_DEFAULT, std::format ("Could not set TCP_NODELAY on socket ({})", strerror (errno))); + log_info (LOG_DEFAULT, "Could not set TCP_NODELAY on socket ({})", strerror (errno)); // not a fatal failure } - log_info (LOG_DEFAULT, std::format ("Successfully received connection from XS on port {}, fd: {}", listen_port, fd)); + log_info (LOG_DEFAULT, "Successfully received connection from XS on port {}, fd: {}", listen_port, fd); need_new_conn = process_connection (fd); } @@ -442,7 +441,7 @@ Debug::process_cmd (int fd, char *cmd) constexpr std::string_view PONG_REPLY { "pong" }; if (strcmp (cmd, PING_CMD.data ()) == 0) { if (!Util::send_uninterrupted (fd, const_cast (reinterpret_cast (PONG_REPLY.data ())), 5)) - log_error (LOG_DEFAULT, std::format ("Got keepalive request from XS, but could not send response back ({})", strerror (errno))); + log_error (LOG_DEFAULT, "Got keepalive request from XS, but could not send response back ({})", strerror (errno)); return false; } @@ -488,7 +487,7 @@ Debug::process_cmd (int fd, char *cmd) profiler_fd = fd; profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { - log_error (LOG_DEFAULT, std::format ("Unknown profiler: '{}'", prof)); + log_error (LOG_DEFAULT, "Unknown profiler: '{}'", prof); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -497,7 +496,7 @@ Debug::process_cmd (int fd, char *cmd) pthread_mutex_unlock (&process_cmd_mutex); return use_fd; } else { - log_error (LOG_DEFAULT, std::format ("Unsupported command: '{}'", cmd)); + log_error (LOG_DEFAULT, "Unsupported command: '{}'", cmd); } return false; @@ -527,7 +526,7 @@ Debug::start_debugging (void) // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); if (enable_soft_breakpoints ()) { constexpr std::string_view soft_breakpoints { "--soft-breakpoints" }; @@ -554,7 +553,7 @@ Debug::start_profiling () if (!profiler_description) return; - log_info (LOG_DEFAULT, std::format ("Loading profiler: '{}'", profiler_description)); + log_info (LOG_DEFAULT, "Loading profiler: '{}'", profiler_description); monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), profiler_description, nullptr); } @@ -574,7 +573,7 @@ Debug::enable_soft_breakpoints (void) uname (&name); for (const char** ptr = soft_breakpoint_kernel_list; *ptr; ptr++) { if (strcmp (name.release, *ptr) == 0) { - log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled due to kernel version match ({})", name.release)); + log_info (LOG_DEBUGGER, "soft breakpoints enabled due to kernel version match ({})", name.release); return 1; } } @@ -582,17 +581,17 @@ Debug::enable_soft_breakpoints (void) char *value; /* Soft breakpoints are enabled by default */ if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS, &value) <= 0) { - log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled by default ({} property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ())); + log_info (LOG_DEBUGGER, "soft breakpoints enabled by default ({} property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); return 1; } bool ret; if (strcmp ("0", value) == 0) { ret = false; - log_info (LOG_DEBUGGER, std::format ("soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); + log_info (LOG_DEBUGGER, "soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); } else { ret = true; - log_info (LOG_DEBUGGER, std::format ("soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value)); + log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); } delete[] value; return ret; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index d195b26fcaf..e0cf5548a5d 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -22,7 +22,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector } auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (assembly_store_map, entry_name.get ()); - log_debug (LOG_ASSEMBLY, std::format ("Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size)); + log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); auto header = static_cast(payload_start); if (header->magic != ASSEMBLY_STORE_MAGIC) { @@ -264,7 +262,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& dynamic_local_string entry_name; bool assembly_store_found = false; - log_debug (LOG_ASSEMBLY, std::format ("Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ())); + log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -300,14 +298,12 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& log_debug ( LOG_ASSEMBLY, - std::format ( - "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", - entry_name.get (), - number_of_zip_dso_entries, - name, - apk_entry->name_hash, - apk_entry->offset - ) + "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", + entry_name.get (), + number_of_zip_dso_entries, + name, + apk_entry->name_hash, + apk_entry->offset ); number_of_zip_dso_entries++; } @@ -331,9 +327,9 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ); } #ifdef DEBUG - log_info (LOG_ASSEMBLY, std::format ("Central directory offset: {}", cd_offset)); - log_info (LOG_ASSEMBLY, std::format ("Central directory size: {}", cd_size)); - log_info (LOG_ASSEMBLY, std::format ("Central directory entries: {}", cd_entries)); + log_info (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); + log_info (LOG_ASSEMBLY, "Central directory size: {}", cd_size); + log_info (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); #endif off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); if (retval < 0) { @@ -411,9 +407,8 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, - std::format ("Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", - entry.file_name, entry.name, entry.data_size - ) + "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", + entry.file_name, entry.name, entry.data_size ); } @@ -435,14 +430,14 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ // The simplest case - no file comment off_t ret = ::lseek (fd, -ZIP_EOCD_LEN, SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); + log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); return false; } std::array eocd; ssize_t nread = ::read (fd, eocd.data (), eocd.size ()); if (nread < 0 || nread != eocd.size ()) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); + log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); return false; } @@ -462,7 +457,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed ret = ::lseek (fd, static_cast(-alloc_size), SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, std::format ("Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno)); + log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); return false; } @@ -471,7 +466,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ nread = ::read (fd, buf.data (), buf.size ()); if (nread < 0 || static_cast(nread) != alloc_size) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno)); + log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); return false; } @@ -505,10 +500,8 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no if (result < 0) { log_error ( LOG_ASSEMBLY, - std::format ( - "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", - state.local_header_offset, std::strerror (errno), result, errno - ) + "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", + state.local_header_offset, std::strerror (errno), result, errno ); return false; } @@ -518,32 +511,32 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); if (nread < 0 || nread != ZIP_LOCAL_LEN) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno)); + log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); return false; } size_t index = 0; if (!zip_read_field (local_header, index, signature)) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header entry signature at offset {}", state.local_header_offset)); + log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); return false; } if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, std::format ("Invalid Local Header entry signature at offset {}", state.local_header_offset)); + log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); return false; } uint16_t file_name_length; index = LH_FILE_NAME_LENGTH_OFFSET; if (!zip_read_field (local_header, index, file_name_length)) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index))); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); return false; } uint16_t extra_field_length; index = LH_EXTRA_LENGTH_OFFSET; if (!zip_read_field (local_header, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, std::format ("Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index))); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); return false; } @@ -585,7 +578,7 @@ force_inline bool EmbeddedAssemblies::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { - log_error (LOG_ASSEMBLY, std::format ("Buffer too short to read {} bytes of data", to_read)); + log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); return false; } diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 2e7580dd398..269bf682783 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -130,7 +130,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb ) ); } else { - log_debug (LOG_ASSEMBLY, std::format ("Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name)); + log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -228,7 +228,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, std::format ("Assembly {} already mmapped by another thread, unmapping our copy", file.name)); + log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", file.name); munmap (map_info.area, file.data_size); map_info.area = nullptr; } @@ -243,18 +243,16 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc header[j] = isprint (p [j]) ? p [j] : '.'; header [header.size () - 1] = '\0'; - log_info_nocheck ( + log_info_nocheck_fmt ( LOG_ASSEMBLY, - std::format ( - "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", - file.data_offset, - static_cast(file.data), - pointer_add (file.data, file.data_size), - file.data_size, - file.name, - file.name, - header.data () - ) + "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", + file.data_offset, + static_cast(file.data), + pointer_add (file.data, file.data_size), + file.data_size, + file.name, + file.name, + header.data () ); } } @@ -289,7 +287,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (strcmp (assembly.name, abi_name.get ()) != 0) { return nullptr; } else { - log_debug (LOG_ASSEMBLY, std::format ("open_from_bundles: found architecture-specific: '{}'", abi_name.get ())); + log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", abi_name.get ()); } } @@ -350,7 +348,7 @@ EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_strin name.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, std::format ("individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ())); + log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ()); dynamic_local_string abi_name; abi_name @@ -397,7 +395,7 @@ template EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { hash_t name_hash = xxhash::hash (name.get (), name.length ()); - log_debug (LOG_ASSEMBLY, std::format ("assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash)); + log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash); const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) { @@ -430,16 +428,15 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string(assembly_runtime_info.image_data), - static_cast(assembly_runtime_info.debug_info_data), - static_cast(assembly_runtime_info.config_data), - static_cast(assembly_runtime_info.descriptor), - assembly_runtime_info.descriptor->data_size, - assembly_runtime_info.descriptor->debug_data_size, - assembly_runtime_info.descriptor->config_data_size, - name.get () - ) + "Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'", + static_cast(assembly_runtime_info.image_data), + static_cast(assembly_runtime_info.debug_info_data), + static_cast(assembly_runtime_info.config_data), + static_cast(assembly_runtime_info.descriptor), + assembly_runtime_info.descriptor->data_size, + assembly_runtime_info.descriptor->debug_data_size, + assembly_runtime_info.descriptor->config_data_size, + name.get () ); } @@ -554,7 +551,7 @@ EmbeddedAssemblies::binary_search (const Key *key, const Entry *base, size_t nme if constexpr (use_precalculated_size) { size = precalculated_size; - log_info (LOG_ASSEMBLY, std::format ("Pre-calculated entry size = {}", size)); + log_info (LOG_ASSEMBLY, "Pre-calculated entry size = {}", size); } while (nmemb > 0) { @@ -623,26 +620,26 @@ EmbeddedAssemblies::typemap_java_to_managed ([[maybe_unused]] hash_t hash, const entry = binary_search (java_type_name.get (), type_map.java_to_managed, type_map.entry_count); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ())); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ()); return nullptr; } const char *managed_type_name = entry->to; if (managed_type_name == nullptr) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ())); + log_debug (LOG_ASSEMBLY, "typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ()); return nullptr; } - log_debug (LOG_DEFAULT, std::format ("typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), managed_type_name)); + log_debug (LOG_DEFAULT, "typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), managed_type_name); MonoType *type = mono_reflection_type_from_name (const_cast(managed_type_name), nullptr); if (type == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, std::format ("typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ())); + log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ()); return nullptr; } MonoReflectionType *ret = mono_type_get_object (Util::get_current_domain (), type); if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type '{}'", managed_type_name)); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '{}'", managed_type_name); return nullptr; } @@ -662,16 +659,16 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java TypeMapModule *module = java_entry != nullptr && java_entry->module_index < map_module_count ? &map_modules[java_entry->module_index] : nullptr; if (module == nullptr) { if (java_entry == nullptr) { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash)); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash); } else { - log_warn (LOG_ASSEMBLY, std::format ("typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index)); + log_warn (LOG_ASSEMBLY, "typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index); } return nullptr; } const TypeMapModuleEntry *entry = binary_search (java_entry->type_token_id, module->map, module->entry_count); if (entry == nullptr) { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ())); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ()); return nullptr; } @@ -679,7 +676,7 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java module->image = mono_image_loaded (module->assembly_name); if (module->image == nullptr) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name)); + log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name); // Fake a request from MonoVM to load the assembly. MonoAssemblyName *assembly_name = mono_assembly_name_new (module->assembly_name); @@ -702,15 +699,15 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (module->image == nullptr) { - log_error (LOG_ASSEMBLY, std::format ("typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ())); + log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ()); return nullptr; } } - log_debug (LOG_ASSEMBLY, std::format ("typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id)); + log_debug (LOG_ASSEMBLY, "typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); MonoClass *klass = mono_class_get (module->image, java_entry->type_token_id); if (klass == nullptr) [[unlikely]] { - log_error (LOG_ASSEMBLY, std::format ("typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); + log_error (LOG_ASSEMBLY, "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); return nullptr; } @@ -721,7 +718,7 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java MonoReflectionType *ret = mono_type_get_object (domain, mono_class_get_type (klass)); if (ret == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ())); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); return nullptr; } @@ -786,7 +783,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapEntry *entry = typemap_managed_to_java (full_name.get ()); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, std::format ("typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ())); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ()); return nullptr; } @@ -807,13 +804,13 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo if (mvid == nullptr) { log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); } else { - log_info (LOG_ASSEMBLY, std::format ("typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ())); + log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ()); } return nullptr; } uint32_t token = mono_class_get_type_token (klass); - log_debug (LOG_ASSEMBLY, std::format ("typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF)); + log_debug (LOG_ASSEMBLY, "typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF); // Each map entry is a pair of 32-bit integers: [TypeTokenID][JavaMapArrayIndex] const TypeMapModuleEntry *entry = match->map != nullptr ? binary_search (token, match->map, match->entry_count) : nullptr; if (entry == nullptr) { @@ -823,41 +820,40 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo } if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token)); + log_debug (LOG_ASSEMBLY, "typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token); entry = binary_search (token, match->duplicate_map, match->duplicate_count); } if (entry == nullptr) { - log_info (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name)); + log_info (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name); return nullptr; } } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index)); + log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index); return nullptr; } TypeMapJava const& java_entry = map_java[entry->java_map_index]; if (java_entry.java_name_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index)); + log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index); return nullptr; } const char *ret = java_type_names[java_entry.java_name_index]; if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("typemap: empty Java type name returned for entry at index {}", entry->java_map_index)); + log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}", entry->java_map_index); } log_debug ( LOG_ASSEMBLY, - std::format ("typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", - token, - token, - MonoGuidString (mvid).get (), - match->assembly_name, - ret - ) + "typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", + token, + token, + MonoGuidString (mvid).get (), + match->assembly_name, + ret ); return ret; @@ -919,7 +915,7 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons log_info ( LOG_ASSEMBLY, - std::format (" mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", mmap_info.area, pointer_add (mmap_info.area, mmap_info.size), mmap_info.size, @@ -928,7 +924,6 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons file_info.size, fd, filename - ) ); return file_info; @@ -948,7 +943,7 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro ) ); } - log_debug (LOG_ASSEMBLY, std::format ("APK {} FD: {}", apk, fd)); + log_debug (LOG_ASSEMBLY, "APK {} FD: {}", apk, fd); zip_load_entries (fd, apk, should_register); } @@ -975,40 +970,40 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char struct stat sbuf; int res = fstatat (dir_fd, file_path, &sbuf, 0); if (res < 0) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); return false; } file_size = static_cast(sbuf.st_size); if (file_size < sizeof (header)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header))); + log_error (LOG_ASSEMBLY, "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header)); return false; } fd = openat (dir_fd, file_path, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno)); return false; } ssize_t nread = do_read (fd, &header, sizeof (header)); if (nread <= 0) { if (nread < 0) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); } else { - log_error (LOG_ASSEMBLY, std::format ("typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path)); + log_error (LOG_ASSEMBLY, "typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path); } return false; } if (header.magic != expected_magic) { - log_error (LOG_ASSEMBLY, std::format ("typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic)); + log_error (LOG_ASSEMBLY, "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic); return false; } if (header.version != MODULE_FORMAT_VERSION) { - log_error (LOG_ASSEMBLY, std::format ("typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version)); + log_error (LOG_ASSEMBLY, "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version); return false; } @@ -1021,14 +1016,14 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ size_t entry_size = header.module_file_name_width; size_t data_size = entry_size * type_map_count; if (sizeof(header) + data_size > file_size) { - log_error (LOG_ASSEMBLY, std::format ("typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size)); + log_error (LOG_ASSEMBLY, "typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size); return nullptr; } auto data = std::make_unique (data_size); ssize_t nread = do_read (index_fd, data.get (), data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno)); return nullptr; } @@ -1044,7 +1039,7 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ std::unique_ptr EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap index file '{}/{}'", dir_path, index_path)); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", dir_path, index_path); TypeMapIndexHeader header; size_t file_size; @@ -1071,7 +1066,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * ssize_t nread = do_read (file_fd, module.assembly_name, header.assembly_name_length); if (nread != static_cast(header.assembly_name_length)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno)); return false; } @@ -1080,16 +1075,14 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, - std::format ( - "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", - dir_path, - file_path, - header.entry_count, - header.java_name_width, - header.managed_name_width, - header.assembly_name_length, - module.assembly_name - ) + "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", + dir_path, + file_path, + header.entry_count, + header.java_name_width, + header.managed_name_width, + header.assembly_name_length, + module.assembly_name ); // [name][index] @@ -1103,7 +1096,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * module.data = new uint8_t [data_size]; nread = do_read (file_fd, module.data, data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno))); + log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno)); return false; } @@ -1147,7 +1140,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * bool EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMap &module) { - log_debug (LOG_ASSEMBLY, std::format ("typemap: loading TypeMap file '{}/{}'", dir_path, file_path)); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", dir_path, file_path); bool ret = true; BinaryTypeMapHeader header; @@ -1186,7 +1179,7 @@ EmbeddedAssemblies::register_from_apk (const char *apk_file, monodroid_should_re gather_bundled_assemblies_from_apk (apk_file, should_register); - log_info (LOG_ASSEMBLY, std::format ("Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev)); + log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev); return number_of_found_assemblies; } @@ -1290,10 +1283,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( [[gnu::always_inline]] size_t EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look_for_mangled_names, monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, std::format ("Looking for assemblies in '{}'", lib_dir_path)); + log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", lib_dir_path); DIR *lib_dir = opendir (lib_dir_path); // TODO: put it in a scope guard at some point if (lib_dir == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno)); return 0; } @@ -1302,14 +1295,14 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno)); closedir (lib_dir); return 0; } state.file_fd = dup (dir_fd); if (state.file_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno)); closedir (lib_dir); return 0; } @@ -1326,7 +1319,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno)); continue; // keep going, no harm } break; // No more entries, we're done @@ -1346,7 +1339,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look // ...and we can handle the runtime config entry if (!runtime_config_blob_found && std::strncmp (cur->d_name, SharedConstants::RUNTIME_CONFIG_BLOB_NAME.data (), SharedConstants::RUNTIME_CONFIG_BLOB_NAME.size ()) == 0) { - log_debug (LOG_ASSEMBLY, std::format ("Mapping runtime config blob from '{}'", cur->d_name)); + log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", cur->d_name); auto file_size = Util::get_file_size_at (state.file_fd, cur->d_name); if (!file_size) { continue; @@ -1393,6 +1386,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, std::format ("Found {} assemblies on the filesystem", assembly_count)); + log_debug (LOG_ASSEMBLY, "Found {} assemblies on the filesystem", assembly_count); return assembly_count; } diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index fe7493506fa..a505721bf23 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -310,7 +310,7 @@ namespace xamarin::android::internal { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, std::format ("Not an ELF image: {}", file_name)); + log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", file_name); // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } @@ -329,7 +329,7 @@ namespace xamarin::android::internal { static void store_mapped_runtime_config_data (md_mmap_info const& map_info, const char *file_name) noexcept { auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (map_info, file_name); - log_debug (LOG_ASSEMBLY, std::format ("Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size)); + log_debug (LOG_ASSEMBLY, "Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size); runtime_config_data = payload_start; runtime_config_data_size = payload_size; runtime_config_blob_found = true; @@ -436,7 +436,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, std::format ("Unmangled name to '{}'", name.get ())); + log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", name.get ()); }; private: diff --git a/src/native/mono/monodroid/monodroid-glue-internal.hh b/src/native/mono/monodroid/monodroid-glue-internal.hh index 8a1e76bf425..2708ac58205 100644 --- a/src/native/mono/monodroid/monodroid-glue-internal.hh +++ b/src/native/mono/monodroid/monodroid-glue-internal.hh @@ -128,7 +128,7 @@ namespace xamarin::android::internal void *symptr = MonodroidDl::monodroid_dlsym (handle, name, &err, nullptr); if (symptr == nullptr) { - log_warn (LOG_DEFAULT, std::format ("Failed to load symbol '{}' library with handle {}. {}", name, handle, err == nullptr ? "Unknown error"sv : err)); + log_warn (LOG_DEFAULT, "Failed to load symbol '{}' library with handle {}. {}", name, handle, err == nullptr ? "Unknown error"sv : err); fnptr = nullptr; return; } diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 65cf8919eea..c01f45dabd1 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -174,12 +174,12 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] fullpath.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, std::format ("open_from_update_dir: trying to open assembly: {}", fullpath.get ())); + log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", 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) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status)); } } else { log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); @@ -191,7 +191,7 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] } if (result != nullptr && Util::should_log (LOG_ASSEMBLY)) { - log_info_nocheck (LOG_ASSEMBLY, std::format ("open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result))); + log_info_nocheck_fmt (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result)); } return result; } @@ -378,7 +378,7 @@ MonodroidRuntime::parse_gdb_options () noexcept time_t secs = time (nullptr); if (v + 10 < secs) { - log_warn (LOG_DEFAULT, std::format ("Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ())); + log_warn (LOG_DEFAULT, "Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); do_wait = false; } } @@ -449,13 +449,13 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, std::format ("Invalid SDB port value {}", sdb_port)); + log_error (LOG_DEFAULT, "Invalid SDB port value {}", sdb_port); ret = false; continue; } if (out_port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, std::format ("Invalid output port value {}", out_port)); + log_error (LOG_DEFAULT, "Invalid output port value {}", out_port); ret = false; continue; } @@ -480,7 +480,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string arg (token); - log_error (LOG_DEFAULT, std::format ("Unknown runtime argument: '{}'", arg.get ())); + log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", arg.get ()); ret = false; } } @@ -509,9 +509,9 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse cur_time = time (nullptr); if (!parse_runtime_args (runtime_args, &options)) { - log_error (LOG_DEFAULT, std::format ("Failed to parse runtime args: '{}'", runtime_args.get ())); + log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", runtime_args.get ()); } else if (options.debug && cur_time > options.timeout_time) { - log_warn (LOG_DEBUGGER, std::format ("Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time)); + log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time); } else if (options.debug && cur_time <= options.timeout_time) { EmbeddedAssemblies::set_register_debug_symbols (true); @@ -537,7 +537,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, std::format ("Trying to initialize the debugger with options: {}", debug_arg)); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); if (options.out_port > 0) { int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -570,7 +570,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (options.server) { int accepted = monodroid_debug_accept (sock, addr); - log_warn (LOG_DEBUGGER, std::format ("Accepted stdout connection: {}", accepted)); + log_warn (LOG_DEBUGGER, "Accepted stdout connection: {}", accepted); if (accepted < 0) { Helpers::abort_application ( LOG_DEBUGGER, @@ -662,7 +662,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; - log_warn (LOG_DEBUGGER, std::format ("passing '{}' as extra arguments to the runtime.", prop_val.get ())); + log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", prop_val.get ()); char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; @@ -730,11 +730,9 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks if (user_assemblies_count == 0 && AndroidSystem::count_override_assemblies () == 0 && !is_running_on_desktop) { #if defined (DEBUG) log_fatal (LOG_DEFAULT, - std::format ( - "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", - AndroidSystem::override_dirs [0], - (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv - ) + "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", + AndroidSystem::override_dirs [0], + (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv ); #else log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"sv); @@ -859,7 +857,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec // GC threshold is 90% of the max GREF count init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); - log_info (LOG_GC, std::format ("GREF GC Threshold: {}", init.grefGcThreshold)); + log_info (LOG_GC, "GREF GC Threshold: {}", init.grefGcThreshold); init.grefClass = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); @@ -945,7 +943,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec auto initialize = reinterpret_cast (mono_method_get_unmanaged_callers_only_ftnptr (method, &error)); if (initialize == nullptr) { - log_fatal (LOG_DEFAULT, std::format ("Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error))); + log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error)); } abort_unless ( @@ -1001,7 +999,7 @@ MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstr if (createDirectory) { int rv = Util::create_directory (value.get_cstr (), mode); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, std::format ("Failed to create directory for environment variable {}. {}", name, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create directory for environment variable {}. {}", name, strerror (errno)); } setenv (name, value.get_cstr (), 1); } @@ -1011,10 +1009,10 @@ MonodroidRuntime::create_xdg_directory (jstring_wrapper& home, size_t home_len, { static_local_string dir (home_len + relative_path.length ()); Util::path_combine (dir, home.get_cstr (), home_len, relative_path.data (), relative_path.length ()); - log_debug (LOG_DEFAULT, std::format ("Creating XDG directory: {}", dir.get ())); + log_debug (LOG_DEFAULT, "Creating XDG directory: {}", dir.get ()); int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, std::format ("Failed to create XDG directory {}. {}", dir.get (), strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", dir.get (), strerror (errno)); if (!environment_variable_name.empty ()) { setenv (environment_variable_name.data (), dir.get (), 1); } @@ -1043,7 +1041,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, std::format ("Env variable '{}' set to '{}'.", name, v)); + log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", name, v); }; string_segment arg_token; @@ -1063,7 +1061,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept log_envvar (arg.get (), one.data ()); } else if (index == 0) { // ’=value’ - log_warn (LOG_DEFAULT, std::format ("Attempt to set environment variable without specifying name: '{}'", arg.get ())); + log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", arg.get ()); } else { // ’name=value’ arg[index] = '\0'; @@ -1143,10 +1141,10 @@ MonodroidRuntime::set_profile_options () noexcept .append (output_path.get (), output_path.length ()); } if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno)); } - log_warn (LOG_DEFAULT, std::format ("Initializing profiler with options: {}", value.get ())); + log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", value.get ()); debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } @@ -1471,7 +1469,7 @@ 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, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); + log_debug (LOG_DEFAULT, "Using runtime path: {}", AndroidSystem::get_runtime_libdir ()); } AndroidSystem::setup_process_args (runtimeApks); @@ -1536,15 +1534,14 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (Util::should_log (LOG_DEFAULT)) [[unlikely]] { log_info_nocheck_fmt ( LOG_DEFAULT, - std::format (".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", - BuildInfo::xa_version.data (), - BuildInfo::architecture.data (), - BuildInfo::kind.data (), - BuildInfo::date.data (), - BuildInfo::ndk_version.data (), - BuildInfo::ndk_api_level.data (), - mono_get_runtime_build_info () - ) + ".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", + BuildInfo::xa_version.data (), + BuildInfo::architecture.data (), + BuildInfo::kind.data (), + BuildInfo::date.data (), + BuildInfo::ndk_version.data (), + BuildInfo::ndk_api_level.data (), + mono_get_runtime_build_info () ); } @@ -1667,7 +1664,7 @@ MonodroidRuntime::get_java_class_name_for_TypeManager (jclass klass) noexcept JNIEnv *env = osBridge.ensure_jnienv (); jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); if (name == nullptr) { - log_error (LOG_DEFAULT, std::format ("Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass))); + log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); return nullptr; } diff --git a/src/native/mono/monodroid/monodroid-networkinfo.cc b/src/native/mono/monodroid/monodroid-networkinfo.cc index f9dcba4c181..4e87c0079d3 100644 --- a/src/native/mono/monodroid/monodroid-networkinfo.cc +++ b/src/native/mono/monodroid/monodroid-networkinfo.cc @@ -88,14 +88,14 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo networkInterface = env->CallStaticObjectMethod (NetworkInterface_class, NetworkInterface_getByName, NetworkInterface_nameArg); env->DeleteLocalRef (NetworkInterface_nameArg); if (env->ExceptionOccurred ()) { - log_warn (LOG_NET, std::format ("Java exception occurred while looking up the interface '{}'", ifname)); + log_warn (LOG_NET, "Java exception occurred while looking up the interface '{}'", ifname); env->ExceptionDescribe (); env->ExceptionClear (); goto leave; } if (!networkInterface) { - log_warn (LOG_NET, std::format ("Failed to look up interface '{}' using Java API", ifname)); + log_warn (LOG_NET, "Failed to look up interface '{}' using Java API", ifname); ret = FALSE; goto leave; } @@ -118,7 +118,7 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo leave: if (!ret) - log_warn (LOG_NET, std::format ("Unable to determine interface '{}' state using Java API", ifname)); + log_warn (LOG_NET, "Unable to determine interface '{}' state using Java API", ifname); if (networkInterface != nullptr && env != nullptr) { env->DeleteLocalRef (networkInterface); diff --git a/src/native/mono/monodroid/monodroid-tracing.cc b/src/native/mono/monodroid/monodroid-tracing.cc index 892a5938393..adb9f0db1d6 100644 --- a/src/native/mono/monodroid/monodroid-tracing.cc +++ b/src/native/mono/monodroid/monodroid-tracing.cc @@ -27,7 +27,7 @@ MonodroidRuntime::log_traces (JNIEnv *env, TraceKind kind, const char *first_lin char *err = nullptr; void *handle = MonodroidDl::monodroid_dlopen (SharedConstants::xamarin_native_tracing_name.data (), MONO_DL_EAGER, &err, nullptr); if (handle == nullptr) { - log_warn (LOG_DEFAULT, std::format ("Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err)); + log_warn (LOG_DEFAULT, "Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err); } else { load_symbol (handle, "xa_get_native_backtrace", _xa_get_native_backtrace); load_symbol (handle, "xa_get_managed_backtrace", _xa_get_managed_backtrace); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 612e6c44c5e..727e277d501 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -186,7 +186,7 @@ OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) *end = '\0'; if ((category == LOG_GREF && gref_to_logcat) || (category == LOG_LREF && lref_to_logcat)) { - log_debug (category, std::format ("{}", m)); + log_debug (category, "{}", m); } if (to != nullptr) { fprintf (to, "%s\n", optional_string (m)); @@ -200,7 +200,7 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, std::format ("{}", message)); + log_debug (LOG_GREF, "{}", message); } if (!gref_log) return; @@ -215,22 +215,21 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH if ((log_categories & LOG_GREF) == 0) return c; log_info (LOG_GREF, - std::format ("+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - threadName, - threadId - ) + "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -261,20 +260,19 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - std::format ("-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - c, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -301,22 +299,21 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - std::format ("+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(curHandle), - curType, - reinterpret_cast(newHandle), - newType, - threadName, - threadId - ) + "+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -345,20 +342,19 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - std::format ("-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", - gc_gref_count, - gc_weak_gref_count, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + gc_gref_count, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!gref_log) @@ -384,19 +380,18 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - std::format ("+l+ lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "+l+ lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!lref_log) @@ -421,19 +416,18 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - std::format ("-l- lrefc {} handle {:p}/{} from thread '{}'({})", - lrefc, - reinterpret_cast(handle), - type, - threadName, - threadId - ) + "-l- lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + threadName, + threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, std::format ("{}", from)); + log_info (LOG_GREF, "{}", from); } } if (!lref_log) @@ -546,11 +540,9 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) i = get_gc_bridge_index (klass); if (i == static_cast (-NUM_GC_BRIDGE_TYPES)) { log_info (LOG_GC, - std::format ( - "asked if a class {}.{} is a bridge before we inited java.lang.Object", - mono_class_get_namespace (klass), - mono_class_get_name (klass) - ) + "asked if a class {}.{} is a bridge before we inited java.lang.Object", + mono_class_get_namespace (klass), + mono_class_get_name (klass) ); return MonoGCBridgeObjectKind::GC_BRIDGE_TRANSPARENT_CLASS; } @@ -576,11 +568,9 @@ OSBridge::gc_is_bridge_object (MonoObject *object) #if DEBUG MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, - std::format ( - "object of class {}.{} with null handle", - mono_class_get_namespace (mclass), - mono_class_get_name (mclass) - ) + "object of class {}.{} with null handle", + mono_class_get_namespace (mclass), + mono_class_get_name (mclass) ); #endif return 0; @@ -667,9 +657,9 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri *reffed_description = describe_target (reffed_target); if (success) - log_warn (LOG_GC, std::format ("Added reference for {} to {}", description, reffed_description)); + log_warn (LOG_GC, "Added reference for {} to {}", description, reffed_description); else - log_error (LOG_GC, std::format ("Missing monodroidAddReference method for {}", description)); + log_error (LOG_GC, "Missing monodroidAddReference method for {}", description); free (description); free (reffed_description); @@ -906,11 +896,9 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (Logger::gc_spew_enabled ()) { klass = mono_object_get_class (obj); log_error (LOG_GC, - std::format ( - "Missing monodroidClearReferences method for object of class {}.{}", - mono_class_get_namespace (klass), - mono_class_get_name (klass) - ) + "Missing monodroidClearReferences method for object of class {}.{}", + mono_class_get_namespace (klass), + mono_class_get_name (klass) ); } #endif @@ -925,7 +913,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } } #if DEBUG - log_info (LOG_GC, std::format ("GC cleanup summary: {} objects tested - resurrecting {}.", total, alive)); + log_info (LOG_GC, "GC cleanup summary: {} objects tested - resurrecting {}.", total, alive); #endif } @@ -955,10 +943,10 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre if (Logger::gc_spew_enabled ()) { int i, j; - log_info (LOG_GC, std::format ("cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs)); + log_info (LOG_GC, "cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs); for (i = 0; i < num_sccs; ++i) { - log_info (LOG_GC, std::format ("group {} with {} objects", i, sccs [i]->num_objs)); + log_info (LOG_GC, "group {} with {} objects", i, sccs [i]->num_objs); for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; @@ -973,21 +961,19 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre } MonoClass *klass = mono_object_get_class (obj); log_info (LOG_GC, - std::format ( - "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", - reinterpret_cast(obj), - mono_class_get_namespace (klass), - mono_class_get_name (klass), - reinterpret_cast(handle), - key_handle - ) + "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", + reinterpret_cast(obj), + mono_class_get_namespace (klass), + mono_class_get_name (klass), + reinterpret_cast(handle), + key_handle ); } } if (Util::should_log (LOG_GC)) { for (i = 0; i < num_xrefs; ++i) - log_info_nocheck (LOG_GC, std::format ("xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index)); + log_info_nocheck_fmt (LOG_GC, "xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); } } diff --git a/src/native/mono/monodroid/xamarin-android-app-context.cc b/src/native/mono/monodroid/xamarin-android-app-context.cc index e55635f2443..75973eb020e 100644 --- a/src/native/mono/monodroid/xamarin-android-app-context.cc +++ b/src/native/mono/monodroid/xamarin-android-app-context.cc @@ -15,7 +15,7 @@ MonodroidRuntime::get_method_name (uint32_t mono_image_index, uint32_t method_to { uint64_t id = (static_cast(mono_image_index) << 32) | method_token; - log_debug (LOG_ASSEMBLY, std::format ("MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index)); + log_debug (LOG_ASSEMBLY, "MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index); size_t i = 0uz; while (mm_method_names[i].id != 0) { if (mm_method_names[i].id == id) { @@ -43,10 +43,9 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas { log_debug ( LOG_ASSEMBLY, - std::format ("MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", - get_method_name (mono_image_index, method_token), method_token, - get_class_name (class_index), class_index - ) + "MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", + get_method_name (mono_image_index, method_token), method_token, + get_class_name (class_index), class_index ); if (class_index >= marshal_methods_number_of_classes) [[unlikely]] { @@ -81,32 +80,29 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, - std::format ("Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", - mono_method_full_name (method, true), - ret, - mono_image_index, - class_index, - method_token - ) + "Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", + mono_method_full_name (method, true), + ret, + mono_image_index, + class_index, + method_token ); return; } log_fatal ( LOG_DEFAULT, - std::format ("Failed to obtain function pointer to method '{}' in class '{}'", - get_method_name (mono_image_index, method_token), - get_class_name (class_index) - ) + "Failed to obtain function pointer to method '{}' in class '{}'", + get_method_name (mono_image_index, method_token), + get_class_name (class_index) ); log_fatal ( LOG_DEFAULT, - std::format ("Looked for image index {}, class index {}, method token {:x}", - mono_image_index, - class_index, - method_token - ) + "Looked for image index {}, class index {}, method token {:x}", + mono_image_index, + class_index, + method_token ); if (image == nullptr) { diff --git a/src/native/mono/monodroid/xamarin_getifaddrs.cc b/src/native/mono/monodroid/xamarin_getifaddrs.cc index 99ba01039e6..57c4935a7bf 100644 --- a/src/native/mono/monodroid/xamarin_getifaddrs.cc +++ b/src/native/mono/monodroid/xamarin_getifaddrs.cc @@ -421,7 +421,7 @@ open_netlink_session (netlink_session *session) memset (session, 0, sizeof (*session)); session->sock_fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (session->sock_fd == -1) { - log_warn (LOG_NETLINK, std::format ("Failed to create a netlink socket. {}", strerror (errno))); + log_warn (LOG_NETLINK, "Failed to create a netlink socket. {}", strerror (errno)); return -1; } @@ -440,7 +440,7 @@ open_netlink_session (netlink_session *session) session->them.nl_family = AF_NETLINK; if (bind (session->sock_fd, (struct sockaddr *)&session->us, sizeof (session->us)) < 0) { - log_warn (LOG_NETLINK, std::format ("Failed to bind to the netlink socket. {}", strerror (errno))); + log_warn (LOG_NETLINK, "Failed to bind to the netlink socket. {}", strerror (errno)); return -1; } @@ -478,7 +478,7 @@ send_netlink_dump_request (netlink_session *session, int type) session->message_header.msg_iov = &session->payload_vector; if (sendmsg (session->sock_fd, (const struct msghdr*)&session->message_header, 0) < 0) { - log_warn (LOG_NETLINK, std::format ("Failed to send netlink message. {}", strerror (errno))); + log_warn (LOG_NETLINK, "Failed to send netlink message. {}", strerror (errno)); return -1; } @@ -529,7 +529,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd abort_if_invalid_pointer_argument (last_ifaddr, "last_ifaddr"); size_t buf_size = static_cast(getpagesize ()); - log_debug (LOG_NETLINK, std::format ("receive buffer size == {}", buf_size)); + log_debug (LOG_NETLINK, "receive buffer size == {}", buf_size); size_t alloc_size = Helpers::multiply_with_overflow_check (sizeof(*response), buf_size); response = (unsigned char*)malloc (alloc_size); @@ -551,10 +551,10 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd netlink_reply.msg_iov = &reply_vector; length = recvmsg (session->sock_fd, &netlink_reply, 0); - log_debug (LOG_NETLINK, std::format (" length == {}", (int)length)); + log_debug (LOG_NETLINK, " length == {}", (int)length); if (length < 0) { - log_debug (LOG_NETLINK, std::format ("Failed to receive reply from netlink. {}", strerror (errno))); + log_debug (LOG_NETLINK, "Failed to receive reply from netlink. {}", strerror (errno)); goto cleanup; } @@ -582,7 +582,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; for (current_message = (struct nlmsghdr*)response; current_message && NLMSG_OK (current_message, static_cast(length)); current_message = NLMSG_NEXT (current_message, length)) { - log_debug (LOG_NETLINK, std::format ("next message... (type: {})", current_message->nlmsg_type)); + log_debug (LOG_NETLINK, "next message... (type: {})", current_message->nlmsg_type); switch (current_message->nlmsg_type) { /* See rtnetlink.h */ case RTM_NEWLINK: @@ -611,7 +611,7 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; default: - log_debug (LOG_NETLINK, std::format (" message type: {}", current_message->nlmsg_type)); + log_debug (LOG_NETLINK, " message type: {}", current_message->nlmsg_type); break; } } @@ -634,7 +634,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET: { struct sockaddr_in *sa4; if (rta_payload_length != 4) /* IPv4 address length */ { - log_warn (LOG_NETLINK, std::format ("Unexpected IPv4 address payload length {}", rta_payload_length)); + log_warn (LOG_NETLINK, "Unexpected IPv4 address payload length {}", rta_payload_length); return -1; } sa4 = (struct sockaddr_in*)calloc (1, sizeof (*sa4)); @@ -650,7 +650,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ case AF_INET6: { struct sockaddr_in6 *sa6; if (rta_payload_length != 16) /* IPv6 address length */ { - log_warn (LOG_NETLINK, std::format ("Unexpected IPv6 address payload length {}", rta_payload_length)); + log_warn (LOG_NETLINK, "Unexpected IPv6 address payload length {}", rta_payload_length); return -1; } sa6 = (struct sockaddr_in6*)calloc (1, sizeof (*sa6)); @@ -668,7 +668,7 @@ fill_sa_address (struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_ default: { struct sockaddr *sagen; if (rta_payload_length > sizeof (sagen->sa_data)) { - log_warn (LOG_NETLINK, std::format ("Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data))); + log_warn (LOG_NETLINK, "Unexpected RTA payload length {} (wanted at most {})", rta_payload_length, sizeof (sagen->sa_data)); return -1; } @@ -701,9 +701,9 @@ fill_ll_address (struct sockaddr_ll_extended **sa, struct ifinfomsg *net_interfa /* The assert can only fail for Iniband links, which are quite unlikely to be found * in any mobile devices */ - log_debug (LOG_NETLINK, std::format ("rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type)); + log_debug (LOG_NETLINK, "rta_payload_length == {}; sizeof sll_addr == {}; hw type == {:x}", rta_payload_length, sizeof ((*sa)->sll_addr), net_interface->ifi_type); if (static_cast(rta_payload_length) > sizeof ((*sa)->sll_addr)) { - log_info (LOG_NETLINK, std::format ("Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr))); + log_info (LOG_NETLINK, "Address is too long to place in sockaddr_ll ({} > {})", rta_payload_length, sizeof ((*sa)->sll_addr)); free (*sa); *sa = NULL; return -1; @@ -817,14 +817,14 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net memset (netmask_data, 0xFF, prefix_bytes); if (postfix_bytes > 0) memset (netmask_data + prefix_bytes + 1, 0x00, postfix_bytes); - log_debug (LOG_NETLINK, std::format (" calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length)); + log_debug (LOG_NETLINK, " calculating netmask, prefix length is {} bits ({} bytes), data length is {} bytes\n", prefix_length, prefix_bytes, data_length); 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 (Util::should_log (LOG_NETLINK)) { log_debug_nocheck (LOG_NETLINK, " netmask is: "sv); for (uint32_t i = 0; i < data_length; i++) { - log_debug_nocheck (LOG_NETLINK, std::format ("{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i])); + log_debug_nocheck_fmt (LOG_NETLINK, "{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i]); } } } @@ -847,7 +847,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if abort_if_invalid_pointer_argument (message, "message"); net_address = reinterpret_cast (NLMSG_DATA (message)); length = static_cast(IFA_PAYLOAD (message)); - log_debug (LOG_NETLINK, std::format (" address data length: {}", length)); + log_debug (LOG_NETLINK, " address data length: {}", length); if (length <= 0) { goto error; } @@ -864,7 +864,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " reading attributes"sv); while (RTA_OK (attribute, length)) { payload_size = RTA_PAYLOAD (attribute); - log_debug (LOG_NETLINK, std::format (" attribute payload_size == {}", payload_size)); + log_debug (LOG_NETLINK, " attribute payload_size == {}", payload_size); sa = NULL; switch (attribute->rta_type) { @@ -943,7 +943,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; default: - log_debug (LOG_NETLINK, std::format (" attribute type: {}", attribute->rta_type)); + log_debug (LOG_NETLINK, " attribute type: {}", attribute->rta_type); break; } @@ -962,7 +962,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " address has no name/label, getting one from interface"sv); ifa->ifa_name = name ? strdup (name) : NULL; } - log_debug (LOG_NETLINK, std::format (" address label: {}", ifa->ifa_name)); + log_debug (LOG_NETLINK, " address label: {}", ifa->ifa_name); if (calculate_address_netmask (ifa, net_address) < 0) { goto error; @@ -1016,13 +1016,13 @@ get_link_info (const struct nlmsghdr *message) goto error; } if (Util::should_log (LOG_NETLINK)) { - log_debug_nocheck (LOG_NETLINK, std::format (" interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name))); - log_debug_nocheck (LOG_NETLINK, std::format (" {}", ifa->ifa_name)); + log_debug_nocheck_fmt (LOG_NETLINK, " interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); + log_debug_nocheck_fmt (LOG_NETLINK, " {}", ifa->ifa_name); } break; case IFLA_BROADCAST: - log_debug (LOG_NETLINK, std::format (" interface broadcast ({} bytes)", RTA_PAYLOAD (attribute))); + log_debug (LOG_NETLINK, " interface broadcast ({} bytes)", RTA_PAYLOAD (attribute)); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1030,7 +1030,7 @@ get_link_info (const struct nlmsghdr *message) break; case IFLA_ADDRESS: - log_debug (LOG_NETLINK, std::format (" interface address ({} bytes)", RTA_PAYLOAD (attribute))); + log_debug (LOG_NETLINK, " interface address ({} bytes)", RTA_PAYLOAD (attribute)); if (fill_ll_address (&sa, net_interface, RTA_DATA (attribute), RTA_PAYLOAD (attribute)) < 0) { goto error; } @@ -1047,7 +1047,7 @@ get_link_info (const struct nlmsghdr *message) attribute = RTA_NEXT (attribute, length); } - log_debug (LOG_NETLINK, std::format ("link flags: {:X}", ifa->ifa_flags)); + log_debug (LOG_NETLINK, "link flags: {:X}", ifa->ifa_flags); return ifa; error: @@ -1142,7 +1142,7 @@ print_ifla_name (int id) int i = 0; while (1) { if (iflas [i].value == -1 && iflas [i].name == 0) { - log_info_nocheck (LOG_NETLINK, std::format ("Unknown ifla->name: unknown id {}", id)); + log_info_nocheck_fmt (LOG_NETLINK, "Unknown ifla->name: unknown id {}", id); break; } @@ -1150,7 +1150,7 @@ print_ifla_name (int id) i++; continue; } - log_info_nocheck (LOG_NETLINK, std::format ("ifla->name: {} ({})", iflas [i].name, iflas [i].value)); + log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", iflas [i].name, iflas [i].value); break; } } @@ -1165,7 +1165,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) char *msg, *tmp; if (!list) { - log_info_nocheck (LOG_NETLINK, std::format ("No list to print in {}", __FUNCTION__)); + log_info_nocheck_fmt (LOG_NETLINK, "No list to print in {}", __FUNCTION__); return; } @@ -1180,7 +1180,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) cur = cur->ifa_next; } - log_info_nocheck (LOG_NETLINK, std::format ("{}: {}", title, msg ? msg : "[no addresses]"sv)); + log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, msg ? msg : "[no addresses]"sv); free (msg); } #endif diff --git a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh index 240223b396c..f6c402c46e7 100644 --- a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh @@ -23,21 +23,21 @@ namespace xamarin::android { constexpr bool PREFER_AOT_CACHE = false; lib_handle = internal::MonodroidDl::monodroid_dlopen (library_name, MONO_DL_LOCAL, nullptr, PREFER_AOT_CACHE); if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name)); + log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name); return nullptr; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, std::format ("Library '{}' handle already cached by another thread", library_name)); + log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", library_name); } } } void *entry_handle = internal::MonodroidDl::monodroid_dlsym (lib_handle, symbol_name, nullptr, nullptr); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name)); + log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name); return nullptr; } @@ -60,7 +60,7 @@ namespace xamarin::android { return nullptr; } - log_debug (LOG_ASSEMBLY, std::format ("Caching p/invoke entry {} @ {}", library_name, entrypoint_name)); + log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); (*api_map)[entrypoint_name] = entry_handle; return entry_handle; } @@ -81,7 +81,7 @@ namespace xamarin::android { ); if (already_loaded) { - log_debug (LOG_ASSEMBLY, std::format ("Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name)); + log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); } } @@ -147,7 +147,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, std::format ("Internal error: null entry in p/invoke map for key '{}'", library_name)); + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", library_name); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index 1ef4bbfaba0..e5c54608ff3 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -22,11 +22,11 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, std::format ("Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash)); + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, std::format ("\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash)); + log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash); } Helpers::abort_application ( LOG_ASSEMBLY, @@ -67,7 +67,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, std::format ("Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name)); + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name); return nullptr; // let Mono deal with the fallout } @@ -75,7 +75,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha } // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below - log_debug (LOG_ASSEMBLY, std::format ("Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name)); + log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name); } return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index d092be238cc..78d59b70bfa 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -65,7 +65,7 @@ AndroidSystem::lookup_system_property (const char *name, size_t &value_len) noex return nullptr; if (application_config.system_property_count % 2 != 0) { - log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count)); + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count); return nullptr; } @@ -138,7 +138,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 = Helpers::add_with_overflow_check (PROPERTY_VALUE_BUFFER_LEN, 1uz); - log_warn (LOG_DEFAULT, std::format ("Buffer to store system property may be too small, will copy only {} bytes", sp_value_len)); + log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); buf = new char [alloc_size]; } @@ -250,12 +250,12 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co } std::unique_ptr override_file {Util::path_combine (od, name)}; - log_info (LOG_DEFAULT, std::format ("Trying to get property from {}", override_file.get ())); + log_info (LOG_DEFAULT, "Trying to get property from {}", 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') { continue; } - log_info (LOG_DEFAULT, std::format ("Property '{}' from {} has value '{}'.", name, od, *value)); + log_info (LOG_DEFAULT, "Property '{}' from {} has value '{}'.", name, od, *value); return result; } #endif // def DEBUG @@ -281,7 +281,7 @@ AndroidSystem::create_update_dir (char *override_dir) noexcept override_dirs [0] = override_dir; Util::create_public_directory (override_dir); - log_warn (LOG_DEFAULT, std::format ("Creating public update directory: `{}`", override_dir)); + log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); } bool @@ -306,16 +306,16 @@ AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exis if (path == nullptr || *path == '\0') return nullptr; - log_info (LOG_ASSEMBLY, std::format ("Trying to load shared library '{}'", path)); + log_info (LOG_ASSEMBLY, "Trying to load shared library '{}'", path); if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { - log_info (LOG_ASSEMBLY, std::format ("Shared library '{}' not found", path)); + log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); return nullptr; } char *error = nullptr; void *handle = java_interop_lib_load (path, dl_flags, &error); if (handle == nullptr && Util::should_log (LOG_ASSEMBLY)) - log_info_nocheck (LOG_ASSEMBLY, std::format ("Failed to load shared library '{}'. {}", path, error)); + log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '{}'. {}", path, error); java_interop_free (error); return handle; } @@ -450,9 +450,9 @@ AndroidSystem::get_max_gref_count_from_system (void) noexcept if (max < 0) max = std::numeric_limits::max (); if (*e) { - log_warn (LOG_GC, std::format ("Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ())); + log_warn (LOG_GC, "Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); } - log_warn (LOG_GC, std::format ("Overriding max JNI Global Reference count to {}", max)); + log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); } return max; } @@ -478,7 +478,7 @@ AndroidSystem::setup_environment (const char *name, const char *value) noexcept if (isupper (name [0]) || name [0] == '_') { if (setenv (name, v, 1) < 0) - log_warn (LOG_DEFAULT, std::format ("(Debug) Failed to set environment variable: {}", strerror (errno))); + log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); return; } @@ -492,13 +492,13 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept struct stat sbuf; if (::stat (path, &sbuf) < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to stat the environment override file {}: {}", path, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to stat the environment override file {}: {}", path, strerror (errno)); return; } int fd = open (path, O_RDONLY); if (fd < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to open the environment override file {}: {}", path, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to open the environment override file {}: {}", path, strerror (errno)); return; } @@ -515,7 +515,7 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept } while (r < 0 && errno == EINTR); if (nread == 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to read the environment override file {}: {}", path, strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to read the environment override file {}: {}", path, strerror (errno)); return; } @@ -536,26 +536,26 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept // # Variable value, terminated with NUL and padded to [value width] with NUL characters // value\0 if (nread < OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) { - log_warn (LOG_DEFAULT, std::format ("Invalid format of the environment override file {}: malformatted header", path)); + log_warn (LOG_DEFAULT, "Invalid format of the environment override file {}: malformatted header", path); return; } char *endptr; unsigned long name_width = strtoul (buf.get (), &endptr, 16); if ((name_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: name width has invalid format", path)); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path); return; } unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, std::format ("Malformed header of the environment override file {}: value width has invalid format", path)); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path); return; } uint64_t data_width = name_width + value_width; if (data_width > file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: invalid data size", path)); + log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path); return; } @@ -563,11 +563,11 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept char *name = buf.get () + OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE; while (data_size > 0 && data_size >= data_width) { if (*name == '\0') { - log_warn (LOG_DEFAULT, std::format ("Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ())); + log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ()); return; } - log_debug (LOG_DEFAULT, std::format ("Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width)); + log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width); setup_environment (name, name + name_width); name += data_width; data_size -= data_width; @@ -602,10 +602,10 @@ AndroidSystem::setup_environment () noexcept } if (aotMode != MonoAotMode::MONO_AOT_MODE_LAST) { - log_debug (LOG_DEFAULT, std::format ("Mono AOT mode: {}", mono_aot_mode_name)); + log_debug (LOG_DEFAULT, "Mono AOT mode: {}", mono_aot_mode_name); } else { if (!is_interpreter_enabled ()) { - log_warn (LOG_DEFAULT, std::format ("Unknown Mono AOT mode: {}", mono_aot_mode_name)); + log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: {}", mono_aot_mode_name); } else { log_warn (LOG_DEFAULT, "Mono AOT mode: interpreter"sv); } @@ -613,7 +613,7 @@ AndroidSystem::setup_environment () noexcept } if (application_config.environment_variable_count % 2 != 0) { - log_warn (LOG_DEFAULT, std::format ("Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count)); + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count); return; } @@ -629,10 +629,10 @@ AndroidSystem::setup_environment () noexcept var_value = ""; #if defined (DEBUG) - log_info (LOG_DEFAULT, std::format ("Setting environment variable '{}' to '{}'", var_name, var_value)); + log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); #endif // def DEBUG if (setenv (var_name, var_value, 1) < 0) - log_warn (LOG_DEFAULT, std::format ("Failed to set environment variable: {}", strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); } #if defined (DEBUG) log_debug (LOG_DEFAULT, "Loading environment from override directories."sv); @@ -641,9 +641,9 @@ AndroidSystem::setup_environment () noexcept continue; } std::unique_ptr env_override_file {Util::path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; - log_debug (LOG_DEFAULT, std::format ("{}", env_override_file.get ())); + log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); if (Util::file_exists (env_override_file.get ())) { - log_debug (LOG_DEFAULT, std::format ("Loading {}", env_override_file.get ())); + log_debug (LOG_DEFAULT, "Loading {}", env_override_file.get ()); setup_environment_from_override_file (env_override_file.get ()); } } @@ -671,12 +671,12 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep { // 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, std::format ("Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ())); + log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); if (!Util::file_exists (libmonodroid_path.get ())) { - log_debug (LOG_ASSEMBLY, std::format ("{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ())); + log_debug (LOG_ASSEMBLY, "{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); set_embedded_dso_mode_enabled (true); } else { - log_debug (LOG_ASSEMBLY, std::format ("Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); + log_debug (LOG_ASSEMBLY, "Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); set_embedded_dso_mode_enabled (false); } } @@ -689,7 +689,7 @@ AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks 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, std::format ("Added filesystem DSO lookup location: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ())); + log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); } else { log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); @@ -725,7 +725,7 @@ AndroidSystem::add_apk_libdir (const char *apk, size_t &index, const char *abi) { 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, std::format ("Added APK DSO lookup location: {}", app_lib_directories[index])); + log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: {}", app_lib_directories[index]); index++; } diff --git a/src/native/mono/runtime-base/monodroid-dl.hh b/src/native/mono/runtime-base/monodroid-dl.hh index 621d0744fe7..93cb8b70b48 100644 --- a/src/native/mono/runtime-base/monodroid-dl.hh +++ b/src/native/mono/runtime-base/monodroid-dl.hh @@ -48,11 +48,11 @@ namespace xamarin::android::internal size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in AOT cache", hash)); + log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, std::format ("Looking for hash {:x} in DSO cache", hash)); + log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } @@ -102,7 +102,7 @@ namespace xamarin::android::internal if (MonodroidState::is_startup_in_progress ()) { auto ignore_component = [&](const char *label, MonoComponent component) -> bool { if ((application_config.mono_components_mask & component) != component) { - log_info (LOG_ASSEMBLY, std::format ("Mono '{}' component requested but not packaged, ignoring", label)); + log_info (LOG_ASSEMBLY, "Mono '{}' component requested but not packaged, ignoring", label); return true; } @@ -150,7 +150,7 @@ namespace xamarin::android::internal } hash_t name_hash = xxhash::hash (name, strlen (name)); - log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash)); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash); DSOCacheEntry *dso = nullptr; if (prefer_aot_cache) { @@ -167,7 +167,7 @@ namespace xamarin::android::internal dso = find_only_dso_cache_entry (name_hash); } - log_debug (LOG_ASSEMBLY, std::format ("monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name)); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name); if (dso == nullptr) { // DSO not known at build time, try to load it @@ -177,7 +177,7 @@ namespace xamarin::android::internal } if (dso->ignore) { - log_info (LOG_ASSEMBLY, std::format ("Request to load '{}' ignored, it is known not to exist", dso->name)); + log_info (LOG_ASSEMBLY, "Request to load '{}' ignored, it is known not to exist", dso->name); return nullptr; } diff --git a/src/native/mono/runtime-base/timing-internal.cc b/src/native/mono/runtime-base/timing-internal.cc index 7b23705d880..6efcfdae461 100644 --- a/src/native/mono/runtime-base/timing-internal.cc +++ b/src/native/mono/runtime-base/timing-internal.cc @@ -78,11 +78,11 @@ FastTiming::dump () noexcept log_write (LOG_TIMING, LogLevel::Info, "[2/4] Accumulated performance results"); ns_to_time (total_assembly_load_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, std::format (" [2/5] Assembly load: {}:{}::{}", sec, ms, ns)); + log_info_nocheck (LOG_TIMING, " [2/5] Assembly load: {}:{}::{}", sec, ms, ns); ns_to_time (total_java_to_managed_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, std::format (" [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns)); + log_info_nocheck (LOG_TIMING, " [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns); ns_to_time (total_managed_to_java_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, std::format (" [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns)); + log_info_nocheck (LOG_TIMING, " [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns); } diff --git a/src/native/mono/runtime-base/timing-internal.hh b/src/native/mono/runtime-base/timing-internal.hh index 804e2544a9d..6389e719e7e 100644 --- a/src/native/mono/runtime-base/timing-internal.hh +++ b/src/native/mono/runtime-base/timing-internal.hh @@ -144,7 +144,7 @@ namespace xamarin::android::internal // likely we'll run out of memory way, way, way before that happens size_t old_size = events.capacity (); events.reserve (old_size << 1); - log_warn (LOG_TIMING, std::format ("Reallocated timing event buffer from {} to {}", old_size, events.size ())); + log_warn (LOG_TIMING, "Reallocated timing event buffer from {} to {}", old_size, events.size ()); } } @@ -246,7 +246,7 @@ namespace xamarin::android::internal [[gnu::always_inline]] bool is_valid_event_index (size_t index, const char *method_name) noexcept { if (index >= events.capacity ()) [[unlikely]] { - log_warn (LOG_TIMING, std::format ("Invalid event index passed to method '{}'", method_name)); + log_warn (LOG_TIMING, "Invalid event index passed to method '{}'", method_name); return false; } diff --git a/src/native/mono/runtime-base/timing.hh b/src/native/mono/runtime-base/timing.hh index 31f9892e918..191ec55df2f 100644 --- a/src/native/mono/runtime-base/timing.hh +++ b/src/native/mono/runtime-base/timing.hh @@ -93,14 +93,14 @@ namespace xamarin::android { timing_diff diff (period); - log_info_nocheck (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); + log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); } static void warn (timing_period const &period, const char *message) noexcept { timing_diff diff (period); - log_warn (LOG_TIMING, std::format (MESSAGE_FORMAT, message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns)); + log_warn (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); } managed_timing_sequence* get_available_sequence () noexcept diff --git a/src/native/mono/runtime-base/util.cc b/src/native/mono/runtime-base/util.cc index 388c9beb9c3..d377cc46c31 100644 --- a/src/native/mono/runtime-base/util.cc +++ b/src/native/mono/runtime-base/util.cc @@ -150,7 +150,7 @@ Util::create_public_directory (const char *dir) mode_t m = umask (0); int ret = mkdir (dir, 0777); if (ret < 0) { - log_warn (LOG_DEFAULT, std::format ("Failed to create directory '{}'. {}", dir, std::strerror (errno))); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); } umask (m); } @@ -198,7 +198,7 @@ Util::set_world_accessable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, std::format ("chmod(\"{}\", 0664) failed: {}", path, strerror (errno))); + log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); } } @@ -211,7 +211,7 @@ Util::set_user_executable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, std::format ("chmod(\"{}\") failed: {}", path, strerror (errno))); + log_error (LOG_DEFAULT, "chmod(\"{}\") failed: {}", path, strerror (errno)); } } @@ -298,7 +298,7 @@ Util::monodroid_fopen (const char *filename, const char *mode) */ ret = fopen (filename, mode); if (ret == nullptr) { - log_error (LOG_DEFAULT, std::format ("fopen failed for file {}: {}", filename, strerror (errno))); + log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); return nullptr; } diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 2c553ff63a6..3dbdeae10bc 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -80,7 +80,7 @@ namespace xamarin::android { struct stat sbuf; if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to stat file '{}': {}", file_name, std::strerror (errno))); + log_warn (LOG_ASSEMBLY, "Failed to stat file '{}': {}", file_name, std::strerror (errno)); return std::nullopt; } @@ -91,7 +91,7 @@ namespace xamarin::android { int fd = openat (dirfd, file_name, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, std::format ("Failed to open file '{}' for reading: {}", file_name, std::strerror (errno))); + log_error (LOG_ASSEMBLY, "Failed to open file '{}' for reading: {}", file_name, std::strerror (errno)); return std::nullopt; } diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index 1c0e5cfd30e..f2f03b9d5b6 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -86,7 +86,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l // 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, std::format ("loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ())); + log_info_nocheck (LOG_DEFAULT, "loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); } namespace xamarin::android diff --git a/src/native/mono/shared/helpers.cc b/src/native/mono/shared/helpers.cc index 645f30e0d84..9638b16ebd5 100644 --- a/src/native/mono/shared/helpers.cc +++ b/src/native/mono/shared/helpers.cc @@ -11,7 +11,7 @@ using namespace xamarin::android; Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept { // Log it, but also... - log_fatal (category, std::string_view { message }); + log_fatal (category, "{}", message); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -35,12 +35,11 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - std::format ("Abort at {}:{}:{} ('%s')", - file_name, - sloc.line (), - sloc.column (), - sloc.function_name () - ) + "Abort at {}:{}:{} ('%s')", + file_name, + sloc.line (), + sloc.column (), + sloc.function_name () ); } std::abort (); diff --git a/src/native/mono/shared/log_functions.cc b/src/native/mono/shared/log_functions.cc index e82f2bd5856..c6d61f54d0d 100644 --- a/src/native/mono/shared/log_functions.cc +++ b/src/native/mono/shared/log_functions.cc @@ -3,8 +3,8 @@ #include -//#include "java-interop-logger.h" -#include "log_types.hh" +#include "java-interop-logger.h" +#include "log_level.hh" // Must match the same ordering as LogCategories static constexpr std::array log_names = { diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index 711317c7a08..1d3dc1ce812 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -48,7 +48,7 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, std::format ("Using runtime path: {}", AndroidSystem::get_runtime_libdir ())); + log_warn (LOG_DEFAULT, "Using runtime path: {}", AndroidSystem::get_runtime_libdir ()); } const char *monosgen_path = get_libmonosgen_path (); @@ -74,10 +74,8 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) break; log_warn (LOG_DEFAULT, - std::format ( - "Copying file `{}` from external location `{}` to internal location `{}`", - file, from_dir, to_dir - ) + "Copying file `{}` from external location `{}` to internal location `{}`", + file, from_dir, to_dir ); to_file = Util::path_combine (to_dir, file); @@ -86,12 +84,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) int r = unlink (to_file); if (r < 0 && errno != ENOENT) { - log_warn (LOG_DEFAULT, std::format ("Unable to delete file `{}`: {}", to_file, strerror (errno))); + log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", to_file, strerror (errno)); break; } if (!Util::file_copy (to_file, from_file)) { - log_warn (LOG_DEFAULT, std::format ("Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno))); + log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno)); break; } @@ -110,22 +108,22 @@ copy_native_libraries_to_internal_location () dirent *e; char *dir_path = Util::path_combine (od, "lib"); - log_warn (LOG_DEFAULT, std::format ("checking directory: `{}`", dir_path)); + log_warn (LOG_DEFAULT, "checking directory: `{}`", dir_path); if (dir_path == nullptr || !Util::directory_exists (dir_path)) { - log_warn (LOG_DEFAULT, std::format ("directory does not exist: `{}`", dir_path)); + log_warn (LOG_DEFAULT, "directory does not exist: `{}`", dir_path); delete[] dir_path; continue; } if ((dir = ::opendir (dir_path)) == nullptr) { - log_warn (LOG_DEFAULT, std::format ("could not open directory: `{}`", dir_path)); + log_warn (LOG_DEFAULT, "could not open directory: `{}`", dir_path); delete[] dir_path; continue; } while ((e = readdir (dir)) != nullptr) { - log_warn (LOG_DEFAULT, std::format ("checking file: `{}`", e->d_name)); + log_warn (LOG_DEFAULT, "checking file: `{}`", 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); } @@ -142,9 +140,9 @@ runtime_exists (const char *dir, char*& libmonoso) return false; libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); - log_warn (LOG_DEFAULT, std::format ("Checking whether Mono runtime exists at: {}", libmonoso)); + log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", libmonoso); if (Util::file_exists (libmonoso)) { - log_info (LOG_DEFAULT, std::format ("Mono runtime found at: {}", libmonoso)); + log_info (LOG_DEFAULT, "Mono runtime found at: {}", libmonoso); return true; } delete[] libmonoso; @@ -196,25 +194,25 @@ get_libmonosgen_path () if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { - log_warn (LOG_DEFAULT, std::format ("symlink exists, recreating: {} -> {}", link, libmonoso)); + log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", link, libmonoso); unlink (link); result = symlink (libmonoso, link); } if (result != 0) - log_warn (LOG_DEFAULT, std::format ("symlink failed with errno={} {}", errno, strerror (errno))); + log_warn (LOG_DEFAULT, "symlink failed with errno={} {}", errno, strerror (errno)); } delete[] libmonoso; libmonoso = link; } - log_warn (LOG_DEFAULT, std::format ("Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv)); + log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv); if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; if (runtime_exists (AndroidSystem::SYSTEM_LIB_PATH.data (), libmonoso)) return libmonoso; - log_fatal (LOG_DEFAULT, std::format ("Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO)); + log_fatal (LOG_DEFAULT, "Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO); for (const char *od : AndroidSystem::override_dirs) { if (od == nullptr) From 25ea6dd0cd1d71cb518ecb85bf50f397be5949da Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 29 Nov 2024 10:01:06 +0100 Subject: [PATCH 048/143] Cleanup --- src/native/mono/runtime-base/internal-pinvokes.hh | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/mono/runtime-base/internal-pinvokes.hh b/src/native/mono/runtime-base/internal-pinvokes.hh index 1fbfc4c1e01..200c7b97204 100644 --- a/src/native/mono/runtime-base/internal-pinvokes.hh +++ b/src/native/mono/runtime-base/internal-pinvokes.hh @@ -3,7 +3,6 @@ #include #include -//#include #include #include From 29e2369c7da39f5539efaf37d9fc49247660e1a8 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 29 Nov 2024 10:11:56 +0100 Subject: [PATCH 049/143] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 14 +++--- .../BuildReleaseArm64XFormsDotNet.apkdesc | 43 +++++++++---------- 2 files changed, 27 insertions(+), 30 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 574f95f396e..be94e0bcbf7 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 @@ -5,7 +5,7 @@ "Size": 3036 }, "classes.dex": { - "Size": 389632 + "Size": 22444 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { "Size": 18296 @@ -14,10 +14,10 @@ "Size": 86352 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 116768 + "Size": 116920 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22416 + "Size": 22408 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24376 @@ -44,7 +44,7 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 903032 + "Size": 1501240 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3196512 @@ -62,10 +62,10 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 13016 + "Size": 18264 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { "Size": 3266 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 2984469 + "PackageSize": 3111445 } \ 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 b408abbf0ce..b3173a6f72f 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 @@ -5,10 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9448880 - }, - "classes2.dex": { - "Size": 154180 + "Size": 9172764 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -35,16 +32,16 @@ "Size": 19544 }, "lib/arm64-v8a/lib_FormsViewGroup.dll.so": { - "Size": 25184 + "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { "Size": 94736 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 522832 + "Size": 524256 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22416 + "Size": 22408 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21448 @@ -173,31 +170,31 @@ "Size": 22096 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { - "Size": 34760 + "Size": 34960 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.AppCompatResources.dll.so": { - "Size": 24296 + "Size": 24512 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.dll.so": { - "Size": 163072 + "Size": 163240 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CardView.dll.so": { "Size": 24560 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CoordinatorLayout.dll.so": { - "Size": 35680 + "Size": 35912 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Core.dll.so": { - "Size": 151216 + "Size": 151408 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CursorAdapter.dll.so": { "Size": 27168 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.DrawerLayout.dll.so": { - "Size": 33760 + "Size": 33944 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Fragment.dll.so": { - "Size": 72224 + "Size": 72528 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Legacy.Support.Core.UI.dll.so": { "Size": 23896 @@ -215,16 +212,16 @@ "Size": 31592 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.RecyclerView.dll.so": { - "Size": 111896 + "Size": 112248 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SavedState.dll.so": { "Size": 23144 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SwipeRefreshLayout.dll.so": { - "Size": 31672 + "Size": 31952 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager.dll.so": { - "Size": 37752 + "Size": 38048 }, "lib/arm64-v8a/lib_Xamarin.Forms.Core.dll.so": { "Size": 581000 @@ -239,7 +236,7 @@ "Size": 80632 }, "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { - "Size": 84400 + "Size": 84768 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 18832 @@ -248,7 +245,7 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 903032 + "Size": 1501240 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3196512 @@ -266,7 +263,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 120016 + "Size": 349440 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -422,7 +419,7 @@ "Size": 1223 }, "META-INF/BNDLTOOL.SF": { - "Size": 98661 + "Size": 98577 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -449,7 +446,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98534 + "Size": 98450 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2489,5 +2486,5 @@ "Size": 812848 } }, - "PackageSize": 10796357 + "PackageSize": 10947851 } \ No newline at end of file From d35774abe913c24bdf0f95b67bd451659ed68747 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 29 Nov 2024 18:10:25 +0100 Subject: [PATCH 050/143] std::format doesn't like null pointers when printing strings --- src/native/mono/monodroid/debug.cc | 22 +- .../mono/monodroid/embedded-assemblies-zip.cc | 23 ++- .../mono/monodroid/embedded-assemblies.cc | 194 +++++++++++++----- .../mono/monodroid/embedded-assemblies.hh | 4 +- .../mono/monodroid/mono-image-loader.hh | 2 +- src/native/mono/monodroid/monodroid-glue.cc | 40 ++-- src/native/mono/monodroid/osbridge.cc | 49 ++--- .../monodroid/xamarin-android-app-context.cc | 10 +- .../mono/monodroid/xamarin_getifaddrs.cc | 8 +- .../pinvoke-override-api-impl.hh | 8 +- .../mono/pinvoke-override/precompiled.cc | 15 +- src/native/mono/runtime-base/logger.cc | 18 +- .../debug-app-helper.cc | 26 +-- 13 files changed, 257 insertions(+), 162 deletions(-) diff --git a/src/native/mono/monodroid/debug.cc b/src/native/mono/monodroid/debug.cc index e72b7aa19a6..492e114704b 100644 --- a/src/native/mono/monodroid/debug.cc +++ b/src/native/mono/monodroid/debug.cc @@ -96,8 +96,8 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (!found) log_warn (LOG_DEFAULT, "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", - mname.get (), - libname.get () + optional_string (mname.get ()), + optional_string (libname.get ()) ); } @@ -109,7 +109,7 @@ bool Debug::load_profiler (void *handle, const char *desc, const char *symbol) { ProfilerInitializer func = reinterpret_cast (java_interop_lib_symbol (handle, symbol, nullptr)); - log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", symbol, reinterpret_cast(func)); + log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", optional_string (symbol), reinterpret_cast(func)); if (func != nullptr) { func (desc); @@ -139,7 +139,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, "Connection options: '{}'", options); + log_info (LOG_DEFAULT, "Connection options: '{}'", optional_string (options)); args = Util::monodroid_strsplit (options, ",", 0); @@ -163,7 +163,7 @@ Debug::parse_options (char *options, ConnOptions *opts) if ((endp == arg) || (*endp != '\0')) log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, "Unknown connection option: '{}'", arg); + log_info (LOG_DEFAULT, "Unknown connection option: '{}'", optional_string (arg)); } } } @@ -275,7 +275,7 @@ Debug::process_connection (int fd) // null-terminate command [cmd_len] = 0; - log_info (LOG_DEFAULT, "Received cmd: '{}'.", command); + log_info (LOG_DEFAULT, "Received cmd: '{}'.", optional_string (command)); if (process_cmd (fd, command)) return true; @@ -487,7 +487,7 @@ Debug::process_cmd (int fd, char *cmd) profiler_fd = fd; profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { - log_error (LOG_DEFAULT, "Unknown profiler: '{}'", prof); + log_error (LOG_DEFAULT, "Unknown profiler: '{}'", optional_string (prof)); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -496,7 +496,7 @@ Debug::process_cmd (int fd, char *cmd) pthread_mutex_unlock (&process_cmd_mutex); return use_fd; } else { - log_error (LOG_DEFAULT, "Unsupported command: '{}'", cmd); + log_error (LOG_DEFAULT, "Unsupported command: '{}'", optional_string (cmd)); } return false; @@ -526,7 +526,7 @@ Debug::start_debugging (void) // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); if (enable_soft_breakpoints ()) { constexpr std::string_view soft_breakpoints { "--soft-breakpoints" }; @@ -588,10 +588,10 @@ Debug::enable_soft_breakpoints (void) bool ret; if (strcmp ("0", value) == 0) { ret = false; - log_info (LOG_DEBUGGER, "soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); + log_info (LOG_DEBUGGER, "soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); } else { ret = true; - log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), value); + log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); } delete[] value; return ret; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index e0cf5548a5d..2cb51ec75e2 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -22,7 +22,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector LOG_ASSEMBLY, std::format ( "Assembly store '{}' is not a valid .NET for Android assembly store file", - entry_name.get () + optional_string (entry_name.get ()) ) ); } @@ -232,7 +237,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string LOG_ASSEMBLY, std::format ( "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", - entry_name.get (), + optional_string (entry_name.get ()), header->version, ASSEMBLY_STORE_FORMAT_VERSION ) @@ -299,9 +304,9 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& log_debug ( LOG_ASSEMBLY, "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", - entry_name.get (), + optional_string (entry_name.get ()), number_of_zip_dso_entries, - name, + optional_string (name), apk_entry->name_hash, apk_entry->offset ); @@ -408,7 +413,9 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", - entry.file_name, entry.name, entry.data_size + optional_string (entry.file_name), + optional_string (entry.name), + entry.data_size ); } diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 269bf682783..95582ce2cc6 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -124,13 +124,13 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!", - name, + optional_string (name), cad.uncompressed_file_size, header->uncompressed_length ) ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name); + log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", optional_string (name)); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -143,7 +143,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} failed with code {}", - name, + optional_string (name), ret ) ); @@ -154,7 +154,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb LOG_ASSEMBLY, std::format ( "Decompression of assembly {} yielded a different size (expected {}, got {})", - name, + optional_string (name), cad.uncompressed_file_size, static_cast(ret) ) @@ -228,7 +228,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", file.name); + log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", optional_string (file.name)); munmap (map_info.area, file.data_size); map_info.area = nullptr; } @@ -250,8 +250,8 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc static_cast(file.data), pointer_add (file.data, file.data_size), file.data_size, - file.name, - file.name, + optional_string (file.name), + optional_string (file.name), header.data () ); } @@ -287,7 +287,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (strcmp (assembly.name, abi_name.get ()) != 0) { return nullptr; } else { - log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", abi_name.get ()); + log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", optional_string (abi_name.get ())); } } @@ -321,7 +321,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (debug_file.data != nullptr) { if (debug_file.data_size > std::numeric_limits::max ()) { - log_warn (LOG_ASSEMBLY, std::format ("Debug info file '{}' is too big for Mono to consume", debug_file.name)); + log_warn (LOG_ASSEMBLY, "Debug info file '{}' is too big for Mono to consume", optional_string (debug_file.name)); } else { mono_debug_open_image_from_memory (image, reinterpret_cast(debug_file.data), static_cast(debug_file.data_size)); } @@ -333,7 +333,7 @@ EmbeddedAssemblies::load_bundled_assembly ( MonoImageOpenStatus status; MonoAssembly *a = mono_assembly_load_from_full (image, name.get (), &status, ref_only); if (a == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to load managed assembly '{}'. {}", name.get (), mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (name.get ()), optional_string (mono_image_strerror (status))); return nullptr; } @@ -348,7 +348,7 @@ EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_strin name.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", name.get ()); + log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", optional_string (name.get ())); dynamic_local_string abi_name; abi_name @@ -395,11 +395,11 @@ template EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { hash_t name_hash = xxhash::hash (name.get (), name.length ()); - log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", name.get (), name_hash); + log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", optional_string (name.get ()), name_hash); const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("Assembly '{}' (hash {:x}) not found", name.get (), name_hash)); + log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.get ()), name_hash); return nullptr; } @@ -436,7 +436,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_stringdata_size, assembly_runtime_info.descriptor->debug_data_size, assembly_runtime_info.descriptor->config_data_size, - name.get () + optional_string (name.get ()) ); } @@ -446,7 +446,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string(managed_type_name), nullptr); if (type == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", managed_type_name, java_type_name.get ()); + log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", optional_string (managed_type_name), java_type_name.get ()); return nullptr; } 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 '{}'", managed_type_name); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '{}'", optional_string (managed_type_name)); return nullptr; } @@ -676,14 +676,14 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java module->image = mono_image_loaded (module->assembly_name); if (module->image == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", module->assembly_name); + log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", optional_string (module->assembly_name)); // Fake a request from MonoVM to load the assembly. MonoAssemblyName *assembly_name = mono_assembly_name_new (module->assembly_name); MonoAssembly *assm; if (assembly_name == nullptr) { - log_error (LOG_ASSEMBLY, std::format ("typemap: failed to create Mono assembly name for '{}'", module->assembly_name)); + log_error (LOG_ASSEMBLY, "typemap: failed to create Mono assembly name for '{}'", optional_string (module->assembly_name)); assm = nullptr; } else { MonoAssemblyLoadContextGCHandle alc_gchandle = mono_alc_get_default_gchandle (); @@ -692,14 +692,14 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (assm == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("typemap: failed to load managed assembly '{}'", module->assembly_name)); + log_warn (LOG_ASSEMBLY, "typemap: failed to load managed assembly '{}'", optional_string (module->assembly_name)); } else { module->image = mono_assembly_get_image (assm); } } if (module->image == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", module->assembly_name, to_utf8 (java_type_name).get ()); + log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", optional_string (module->assembly_name), to_utf8 (java_type_name).get ()); return nullptr; } } @@ -707,7 +707,13 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java log_debug (LOG_ASSEMBLY, "typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); MonoClass *klass = mono_class_get (module->image, java_entry->type_token_id); if (klass == nullptr) [[unlikely]] { - log_error (LOG_ASSEMBLY, "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); + log_error ( + LOG_ASSEMBLY, + "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", + java_entry->type_token_id, + optional_string (module->assembly_name), + to_utf8 (java_type_name).get () + ); return nullptr; } @@ -718,7 +724,12 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java MonoReflectionType *ret = mono_type_get_object (domain, mono_class_get_type (klass)); if (ret == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", java_entry->type_token_id, module->assembly_name, to_utf8 (java_type_name).get ()); + log_warn (LOG_ASSEMBLY, + "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", + java_entry->type_token_id, + optional_string (module->assembly_name), + to_utf8 (java_type_name).get () + ); return nullptr; } @@ -783,7 +794,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapEntry *entry = typemap_managed_to_java (full_name.get ()); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", full_name.get ()); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", optional_string (full_name.get ())); return nullptr; } @@ -815,7 +826,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapModuleEntry *entry = match->map != nullptr ? binary_search (token, match->map, match->entry_count) : nullptr; if (entry == nullptr) { if (match->map == nullptr) { - log_warn (LOG_ASSEMBLY, std::format ("typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ())); + log_warn (LOG_ASSEMBLY, "typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ()); return nullptr; } @@ -831,13 +842,30 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index); + log_warn ( + LOG_ASSEMBLY, + "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", + token, + token, + MonoGuidString (mvid).get (), + optional_string (match->assembly_name), + entry->java_map_index + ); return nullptr; } TypeMapJava const& java_entry = map_java[entry->java_map_index]; if (java_entry.java_name_index >= java_type_count) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", token, token, MonoGuidString (mvid).get (), match->assembly_name, entry->java_map_index, java_entry.java_name_index); + log_warn ( + LOG_ASSEMBLY, + "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", + token, + token, + MonoGuidString (mvid).get (), + optional_string (match->assembly_name), + entry->java_map_index, + java_entry.java_name_index + ); return nullptr; } const char *ret = java_type_names[java_entry.java_name_index]; @@ -852,7 +880,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo token, token, MonoGuidString (mvid).get (), - match->assembly_name, + optional_string (match->assembly_name), ret ); @@ -923,7 +951,7 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons pointer_add (file_info.area, file_info.size), file_info.size, fd, - filename + optional_string (filename) ); return file_info; @@ -939,11 +967,11 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro LOG_ASSEMBLY, std::format ( "ERROR: Unable to load application package {}.", - apk + optional_string (apk) ) ); } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", apk, fd); + log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk), fd); zip_load_entries (fd, apk, should_register); } @@ -970,40 +998,90 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char struct stat sbuf; int res = fstatat (dir_fd, file_path, &sbuf, 0); if (res < 0) { - log_error (LOG_ASSEMBLY, "typemap: failed to stat {} file '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to stat {} file '{}/{}': {}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); return false; } file_size = static_cast(sbuf.st_size); if (file_size < sizeof (header)) { - log_error (LOG_ASSEMBLY, "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", file_type, dir_path, file_path, sizeof (header)); + log_error ( + LOG_ASSEMBLY, + "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + sizeof (header) + ); return false; } fd = openat (dir_fd, file_path, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, "typemap: failed to open {} file {}/{} for reading: {}", file_type, dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to open {} file {}/{} for reading: {}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); return false; } ssize_t nread = do_read (fd, &header, sizeof (header)); if (nread <= 0) { if (nread < 0) { - log_error (LOG_ASSEMBLY, "typemap: failed to read {} file header from '{}/{}': {}", file_type, dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to read {} file header from '{}/{}': {}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); } else { - log_error (LOG_ASSEMBLY, "typemap: end of file while reading {} file header from '{}/{}'", file_type, dir_path, file_path); + log_error ( + LOG_ASSEMBLY, + "typemap: end of file while reading {} file header from '{}/{}'", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path) + ); } return false; } if (header.magic != expected_magic) { - log_error (LOG_ASSEMBLY, "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", file_type, dir_path, file_path, expected_magic, header.magic); + log_error ( + LOG_ASSEMBLY, + "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", + optional_string (file_type), + optional_string (dir_path), + optional_string (file_path), + expected_magic, + header.magic + ); return false; } if (header.version != MODULE_FORMAT_VERSION) { - log_error (LOG_ASSEMBLY, "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", file_type, MODULE_FORMAT_VERSION, dir_path, file_path, header.version); + log_error ( + LOG_ASSEMBLY, + "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", + optional_string (file_type), + MODULE_FORMAT_VERSION, + optional_string (dir_path), + optional_string (file_path), + header.version + ); return false; } @@ -1039,7 +1117,7 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ std::unique_ptr EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", dir_path, index_path); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", optional_string (dir_path), optional_string (index_path)); TypeMapIndexHeader header; size_t file_size; @@ -1066,7 +1144,13 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * ssize_t nread = do_read (file_fd, module.assembly_name, header.assembly_name_length); if (nread != static_cast(header.assembly_name_length)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read map assembly name from '{}/{}': {}", dir_path, file_path, strerror (errno)); + log_error ( + LOG_ASSEMBLY, + "typemap: failed to read map assembly name from '{}/{}': {}", + optional_string (dir_path), + optional_string (file_path), + strerror (errno) + ); return false; } @@ -1076,13 +1160,13 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", - dir_path, - file_path, + optional_string (dir_path), + optional_string (file_path), header.entry_count, header.java_name_width, header.managed_name_width, header.assembly_name_length, - module.assembly_name + optional_string (module.assembly_name) ); // [name][index] @@ -1096,7 +1180,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * module.data = new uint8_t [data_size]; nread = do_read (file_fd, module.data, data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", dir_path, file_path, strerror (errno)); + log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", optional_string (dir_path), optional_string (file_path), strerror (errno)); return false; } @@ -1140,7 +1224,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * bool EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMap &module) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", dir_path, file_path); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", optional_string (dir_path), optional_string (file_path)); bool ret = true; BinaryTypeMapHeader header; @@ -1179,7 +1263,7 @@ EmbeddedAssemblies::register_from_apk (const char *apk_file, monodroid_should_re gather_bundled_assemblies_from_apk (apk_file, should_register); - log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", apk_file, number_of_found_assemblies - prev); + log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", optional_string (apk_file), number_of_found_assemblies - prev); return number_of_found_assemblies; } @@ -1283,10 +1367,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( [[gnu::always_inline]] size_t EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look_for_mangled_names, monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", lib_dir_path); + log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", optional_string (lib_dir_path)); DIR *lib_dir = opendir (lib_dir_path); // TODO: put it in a scope guard at some point if (lib_dir == nullptr) { - log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); return 0; } @@ -1295,14 +1379,14 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); closedir (lib_dir); return 0; } state.file_fd = dup (dir_fd); if (state.file_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, optional_string (lib_dir_path), std::strerror (errno)); closedir (lib_dir); return 0; } @@ -1319,7 +1403,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", lib_dir_path, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); continue; // keep going, no harm } break; // No more entries, we're done @@ -1339,7 +1423,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look // ...and we can handle the runtime config entry if (!runtime_config_blob_found && std::strncmp (cur->d_name, SharedConstants::RUNTIME_CONFIG_BLOB_NAME.data (), SharedConstants::RUNTIME_CONFIG_BLOB_NAME.size ()) == 0) { - log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", cur->d_name); + log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", optional_string (cur->d_name)); auto file_size = Util::get_file_size_at (state.file_fd, cur->d_name); if (!file_size) { continue; diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index a505721bf23..bbb91157b10 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -310,7 +310,7 @@ namespace xamarin::android::internal { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", file_name); + log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", optional_string (file_name)); // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } @@ -436,7 +436,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", name.get ()); + log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", optional_string (name.get ())); }; private: diff --git a/src/native/mono/monodroid/mono-image-loader.hh b/src/native/mono/monodroid/mono-image-loader.hh index e8211259ca9..ac33fe53588 100644 --- a/src/native/mono/monodroid/mono-image-loader.hh +++ b/src/native/mono/monodroid/mono-image-loader.hh @@ -110,7 +110,7 @@ namespace xamarin::android::internal { force_inline static MonoImage* stash_and_return (MonoImage *image, MonoImageOpenStatus status, [[maybe_unused]] hash_t hash) noexcept { if (image == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, std::format ("Failed to open assembly image. {}", mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to open assembly image. {}", optional_string (mono_image_strerror (status))); return nullptr; } diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index c01f45dabd1..135c296a61a 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -174,12 +174,12 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] fullpath.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", fullpath.get ()); + log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", optional_string (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) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", fullpath.get (), mono_image_strerror (status)); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (fullpath.get ()), mono_image_strerror (status)); } } else { log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); @@ -480,7 +480,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string arg (token); - log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", arg.get ()); + log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", optional_string (arg.get ())); ret = false; } } @@ -509,7 +509,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse cur_time = time (nullptr); if (!parse_runtime_args (runtime_args, &options)) { - log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", runtime_args.get ()); + log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", optional_string (runtime_args.get ())); } else if (options.debug && cur_time > options.timeout_time) { log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time); } else if (options.debug && cur_time <= options.timeout_time) { @@ -537,7 +537,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", debug_arg); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); if (options.out_port > 0) { int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -576,7 +576,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse LOG_DEBUGGER, std::format ( "Error accepting stdout and stderr ({}:{}): {}", - options.host, + optional_string (options.host), options.out_port, strerror (errno) ) @@ -591,7 +591,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse LOG_DEBUGGER, std::format ( "Error connecting stdout and stderr ({}:{}): {}", - options.host, + optional_string (options.host), options.out_port, strerror (errno) ) @@ -662,7 +662,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; - log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", prop_val.get ()); + log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", optional_string (prop_val.get ())); char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; @@ -731,8 +731,8 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks #if defined (DEBUG) log_fatal (LOG_DEFAULT, "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", - AndroidSystem::override_dirs [0], - (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? AndroidSystem::override_dirs [1] : ""sv + optional_string (AndroidSystem::override_dirs [0]), + (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? optional_string (AndroidSystem::override_dirs [1]) : "" ); #else log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"sv); @@ -741,7 +741,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks Helpers::abort_application ( std::format ( "ALL entries in APK named `{}` MUST be STORED. Gradle's minification may COMPRESS such entries.", - assemblies_prefix + optional_string (assemblies_prefix) ) ); } @@ -943,7 +943,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec auto initialize = reinterpret_cast (mono_method_get_unmanaged_callers_only_ftnptr (method, &error)); if (initialize == nullptr) { - log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", mono_error_get_message (&error)); + log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", optional_string (mono_error_get_message (&error))); } abort_unless ( @@ -999,7 +999,7 @@ MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstr if (createDirectory) { 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 {}. {}", name, strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory for environment variable {}. {}", optional_string (name), strerror (errno)); } setenv (name, value.get_cstr (), 1); } @@ -1009,10 +1009,10 @@ MonodroidRuntime::create_xdg_directory (jstring_wrapper& home, size_t home_len, { static_local_string dir (home_len + 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: {}", dir.get ()); + log_debug (LOG_DEFAULT, "Creating XDG directory: {}", optional_string (dir.get ())); int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", dir.get (), strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", optional_string (dir.get ()), strerror (errno)); if (!environment_variable_name.empty ()) { setenv (environment_variable_name.data (), dir.get (), 1); } @@ -1041,7 +1041,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", name, v); + log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", optional_string (name), optional_string (v)); }; string_segment arg_token; @@ -1061,7 +1061,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept log_envvar (arg.get (), one.data ()); } else if (index == 0) { // ’=value’ - log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", arg.get ()); + log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", optional_string (arg.get ())); } else { // ’name=value’ arg[index] = '\0'; @@ -1141,10 +1141,10 @@ MonodroidRuntime::set_profile_options () noexcept .append (output_path.get (), output_path.length ()); } if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", AndroidSystem::override_dirs[0], std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); } - log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", value.get ()); + log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", optional_string (value.get ())); debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } @@ -1469,7 +1469,7 @@ 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: {}", AndroidSystem::get_runtime_libdir ()); + log_debug (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); } AndroidSystem::setup_process_args (runtimeApks); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 727e277d501..919506d3fda 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -186,7 +186,7 @@ OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) *end = '\0'; if ((category == LOG_GREF && gref_to_logcat) || (category == LOG_LREF && lref_to_logcat)) { - log_debug (category, "{}", m); + log_debug (category, "{}", optional_string (m)); } if (to != nullptr) { fprintf (to, "%s\n", optional_string (m)); @@ -200,7 +200,7 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, "{}", message); + log_debug (LOG_GREF, "{}", optional_string (message)); } if (!gref_log) return; @@ -214,6 +214,7 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH int c = _monodroid_gref_inc (); if ((log_categories & LOG_GREF) == 0) return c; + log_info (LOG_GREF, "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", c, @@ -222,14 +223,14 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH curType, reinterpret_cast(newHandle), newType, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -265,14 +266,14 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr gc_weak_gref_count, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -306,14 +307,14 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new curType, reinterpret_cast(newHandle), newType, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -347,14 +348,14 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th gc_weak_gref_count, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -384,14 +385,14 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c lrefc, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!lref_log) @@ -420,14 +421,14 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons lrefc, reinterpret_cast(handle), type, - threadName, + optional_string (threadName), threadId ); if (lref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!lref_log) @@ -541,8 +542,8 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) if (i == static_cast (-NUM_GC_BRIDGE_TYPES)) { log_info (LOG_GC, "asked if a class {}.{} is a bridge before we inited java.lang.Object", - mono_class_get_namespace (klass), - mono_class_get_name (klass) + optional_string (mono_class_get_namespace (klass)), + optional_string (mono_class_get_name (klass)) ); return MonoGCBridgeObjectKind::GC_BRIDGE_TRANSPARENT_CLASS; } @@ -569,8 +570,8 @@ OSBridge::gc_is_bridge_object (MonoObject *object) MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, "object of class {}.{} with null handle", - mono_class_get_namespace (mclass), - mono_class_get_name (mclass) + optional_string (mono_class_get_namespace (mclass)), + optional_string (mono_class_get_name (mclass)) ); #endif return 0; @@ -657,9 +658,9 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri *reffed_description = describe_target (reffed_target); if (success) - log_warn (LOG_GC, "Added reference for {} to {}", description, reffed_description); + log_warn (LOG_GC, "Added reference for {} to {}", optional_string (description), optional_string (reffed_description)); else - log_error (LOG_GC, "Missing monodroidAddReference method for {}", description); + log_error (LOG_GC, "Missing monodroidAddReference method for {}", optional_string (description)); free (description); free (reffed_description); @@ -897,8 +898,8 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri klass = mono_object_get_class (obj); log_error (LOG_GC, "Missing monodroidClearReferences method for object of class {}.{}", - mono_class_get_namespace (klass), - mono_class_get_name (klass) + optional_string (mono_class_get_namespace (klass)), + optional_string (mono_class_get_name (klass)) ); } #endif @@ -963,8 +964,8 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre log_info (LOG_GC, "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", reinterpret_cast(obj), - mono_class_get_namespace (klass), - mono_class_get_name (klass), + optional_string (mono_class_get_namespace (klass)), + optional_string (mono_class_get_name (klass)), reinterpret_cast(handle), key_handle ); diff --git a/src/native/mono/monodroid/xamarin-android-app-context.cc b/src/native/mono/monodroid/xamarin-android-app-context.cc index 75973eb020e..9ef193ddeb7 100644 --- a/src/native/mono/monodroid/xamarin-android-app-context.cc +++ b/src/native/mono/monodroid/xamarin-android-app-context.cc @@ -44,8 +44,8 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, "MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", - get_method_name (mono_image_index, method_token), method_token, - get_class_name (class_index), class_index + optional_string (get_method_name (mono_image_index, method_token)), method_token, + optional_string (get_class_name (class_index)), class_index ); if (class_index >= marshal_methods_number_of_classes) [[unlikely]] { @@ -81,7 +81,7 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, "Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", - mono_method_full_name (method, true), + optional_string (mono_method_full_name (method, true)), ret, mono_image_index, class_index, @@ -93,8 +93,8 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_fatal ( LOG_DEFAULT, "Failed to obtain function pointer to method '{}' in class '{}'", - get_method_name (mono_image_index, method_token), - get_class_name (class_index) + optional_string (get_method_name (mono_image_index, method_token)), + optional_string (get_class_name (class_index)) ); log_fatal ( diff --git a/src/native/mono/monodroid/xamarin_getifaddrs.cc b/src/native/mono/monodroid/xamarin_getifaddrs.cc index 57c4935a7bf..23848f9910b 100644 --- a/src/native/mono/monodroid/xamarin_getifaddrs.cc +++ b/src/native/mono/monodroid/xamarin_getifaddrs.cc @@ -962,7 +962,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if log_debug (LOG_NETLINK, " address has no name/label, getting one from interface"sv); ifa->ifa_name = name ? strdup (name) : NULL; } - log_debug (LOG_NETLINK, " address label: {}", ifa->ifa_name); + log_debug (LOG_NETLINK, " address label: {}", optional_string (ifa->ifa_name)); if (calculate_address_netmask (ifa, net_address) < 0) { goto error; @@ -1017,7 +1017,7 @@ get_link_info (const struct nlmsghdr *message) } if (Util::should_log (LOG_NETLINK)) { log_debug_nocheck_fmt (LOG_NETLINK, " interface name (payload length: {}; string length: {})", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); - log_debug_nocheck_fmt (LOG_NETLINK, " {}", ifa->ifa_name); + log_debug_nocheck_fmt (LOG_NETLINK, " {}", optional_string (ifa->ifa_name)); } break; @@ -1150,7 +1150,7 @@ print_ifla_name (int id) i++; continue; } - log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", iflas [i].name, iflas [i].value); + log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", optional_string (iflas [i].name), iflas [i].value); break; } } @@ -1180,7 +1180,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) cur = cur->ifa_next; } - log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, msg ? msg : "[no addresses]"sv); + log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, optional_string (msg, "[no addresses]")); free (msg); } #endif diff --git a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh index f6c402c46e7..259a0d5c879 100644 --- a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh @@ -23,21 +23,21 @@ namespace xamarin::android { constexpr bool PREFER_AOT_CACHE = false; lib_handle = internal::MonodroidDl::monodroid_dlopen (library_name, MONO_DL_LOCAL, nullptr, PREFER_AOT_CACHE); if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name); + log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", optional_string (library_name), optional_string (symbol_name)); return nullptr; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", library_name); + log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", optional_string (library_name)); } } } void *entry_handle = internal::MonodroidDl::monodroid_dlsym (lib_handle, symbol_name, nullptr, nullptr); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name); + log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", optional_string (library_name), optional_string (symbol_name)); return nullptr; } @@ -147,7 +147,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", library_name); + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", optional_string (library_name)); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index e5c54608ff3..29ac736e433 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -22,18 +22,19 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash); + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", + optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", e.name, e.func, e.hash); + log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", optional_string (e.name), e.func, e.hash); } Helpers::abort_application ( LOG_ASSEMBLY, std::format ( "Failure handling a p/invoke request for '{}'@'{}'", - entrypoint_name, - library_name + optional_string (entrypoint_name), + optional_string (library_name) ) ); } @@ -67,7 +68,8 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", entrypoint_name, library_name); + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", + optional_string (entrypoint_name), optional_string (library_name)); return nullptr; // let Mono deal with the fallout } @@ -75,7 +77,8 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha } // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below - log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", entrypoint_name, library_name); + log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", + optional_string (entrypoint_name), optional_string (library_name)); } return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); diff --git a/src/native/mono/runtime-base/logger.cc b/src/native/mono/runtime-base/logger.cc index de5f6dee5cf..92c3137cd7a 100644 --- a/src/native/mono/runtime-base/logger.cc +++ b/src/native/mono/runtime-base/logger.cc @@ -29,13 +29,11 @@ namespace { if (path && access (path, W_OK) < 0) { log_warn (category, - std::format ( - "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", - path, - strerror (errno), - override_dir, - filename - ) + "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", + optional_string (path), + strerror (errno), + optional_string (override_dir), + optional_string (filename) ); path = NULL; } @@ -53,7 +51,7 @@ namespace { if (f) { Util::set_world_accessable (path); } else { - log_warn (category, std::format ("Could not open path '{}' for logging: {}", path, strerror (errno))); + log_warn (category, "Could not open path '{}' for logging: {}", optional_string (path), strerror (errno)); } free (p); @@ -79,12 +77,12 @@ Logger::set_debugger_log_level (const char *level) noexcept unsigned long v = strtoul (level, nullptr, 0); if (v == std::numeric_limits::max () && errno == ERANGE) { - log_error (LOG_DEFAULT, std::format ("Invalid debugger log level value '{}', expecting a positive integer or zero", level)); + log_error (LOG_DEFAULT, "Invalid debugger log level value '{}', expecting a positive integer or zero", level); return; } if (v > std::numeric_limits::max ()) { - log_warn (LOG_DEFAULT, std::format ("Debugger log level value is higher than the maximum of {}, resetting to the maximum value.", std::numeric_limits::max ())); + log_warn (LOG_DEFAULT, "Debugger log level value is higher than the maximum of {}, resetting to the maximum value.", std::numeric_limits::max ()); v = std::numeric_limits::max (); } diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index 1d3dc1ce812..e64c42750c8 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -48,7 +48,7 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, "Using runtime path: {}", AndroidSystem::get_runtime_libdir ()); + log_warn (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); } const char *monosgen_path = get_libmonosgen_path (); @@ -75,7 +75,9 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) log_warn (LOG_DEFAULT, "Copying file `{}` from external location `{}` to internal location `{}`", - file, from_dir, to_dir + optional_string (file), + optional_string (from_dir), + optional_string (to_dir) ); to_file = Util::path_combine (to_dir, file); @@ -84,12 +86,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) int r = unlink (to_file); if (r < 0 && errno != ENOENT) { - log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", to_file, strerror (errno)); + log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", optional_string (to_file), strerror (errno)); break; } if (!Util::file_copy (to_file, from_file)) { - log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", from_file, to_file, strerror (errno)); + log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", optional_string (from_file), optional_string (to_file), strerror (errno)); break; } @@ -108,22 +110,22 @@ copy_native_libraries_to_internal_location () dirent *e; char *dir_path = Util::path_combine (od, "lib"); - log_warn (LOG_DEFAULT, "checking directory: `{}`", dir_path); + log_warn (LOG_DEFAULT, "checking directory: `{}`", optional_string (dir_path)); if (dir_path == nullptr || !Util::directory_exists (dir_path)) { - log_warn (LOG_DEFAULT, "directory does not exist: `{}`", dir_path); + log_warn (LOG_DEFAULT, "directory does not exist: `{}`", optional_string (dir_path)); delete[] dir_path; continue; } if ((dir = ::opendir (dir_path)) == nullptr) { - log_warn (LOG_DEFAULT, "could not open directory: `{}`", dir_path); + log_warn (LOG_DEFAULT, "could not open directory: `{}`", optional_string (dir_path)); delete[] dir_path; continue; } while ((e = readdir (dir)) != nullptr) { - log_warn (LOG_DEFAULT, "checking file: `{}`", e->d_name); + log_warn (LOG_DEFAULT, "checking file: `{}`", optional_string (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); } @@ -140,9 +142,9 @@ runtime_exists (const char *dir, char*& libmonoso) return false; libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); - log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", libmonoso); + log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", optional_string (libmonoso)); if (Util::file_exists (libmonoso)) { - log_info (LOG_DEFAULT, "Mono runtime found at: {}", libmonoso); + log_info (LOG_DEFAULT, "Mono runtime found at: {}", optional_string (libmonoso)); return true; } delete[] libmonoso; @@ -194,7 +196,7 @@ get_libmonosgen_path () if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { - log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", link, libmonoso); + log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", optional_string (link), optional_string (libmonoso)); unlink (link); result = symlink (libmonoso, link); } @@ -205,7 +207,7 @@ get_libmonosgen_path () libmonoso = link; } - log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", libmonoso != nullptr ? libmonoso : ""sv); + log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", optional_string (libmonoso)); if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; From 95bfbcb6eba67ece0ce7268d922401cd5a5b74f7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 3 Dec 2024 13:38:51 +0100 Subject: [PATCH 051/143] Address feedback --- src/native/mono/shared/cpp-util.hh | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index f2f03b9d5b6..abbaa95bb79 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -33,6 +33,50 @@ namespace xamarin::android::detail { va_end (ap); return ret == -1 ? "Out of memory" : message; } + + [[gnu::always_inline]] + static inline std::string get_function_name (const char *signature) + { + using std::operator""sv; + + std::string_view sig { signature }; + if (sig.length () == 0) { + return ""; + } + + auto splitSignature = sig | std::views::split ("::"sv) | std::ranges::to> (); + + std::string ret; + if (splitSignature.size () > 1) { + ret.append (splitSignature [splitSignature.size () - 2]); + ret.append ("::"sv); + } + std::string_view func_name { splitSignature[splitSignature.size () - 1] }; + std::string_view::size_type args_pos = func_name.find ('('); + std::string_view::size_type name_start_pos = func_name.find (' '); + + if (name_start_pos == std::string_view::npos) { + name_start_pos = 0; + } else { + name_start_pos++; // point to after the space which separates return type from name + if (name_start_pos >= func_name.length ()) [[unlikely]] { + name_start_pos = 0; + } + } + + if (args_pos == std::string_view::npos) { + ret.append (func_name.substr (name_start_pos)); + } else { + // If there's a snafu with positions, start from 0 + if (name_start_pos >= args_pos || name_start_pos > func_name.length ()) [[unlikely]] { + name_start_pos = 0; + } + + ret.append (func_name.substr (name_start_pos, args_pos - name_start_pos)); + } + + return ret; + } } template F> @@ -66,7 +110,13 @@ abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_loc { abort_unless ( ptr != nullptr, - [&ptr_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", ptr_name); }, + [&ptr_name, &sloc] { + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a valid pointer", + xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), + ptr_name + ); + }, sloc ); } @@ -77,7 +127,13 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l { abort_unless ( arg > 0, - [&arg_name] { return xamarin::android::detail::_format_message ("Parameter '%s' must be a valid pointer", arg_name); }, + [&arg_name, &sloc] { + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a valid pointer", + xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), + arg_name + ); + }, sloc ); } From 96c656410445f81943387f47497d3a569f64e0a7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 10 Jan 2025 21:27:55 +0100 Subject: [PATCH 052/143] Add the CoreCLR runtime falvor The build is broken atm, need to move things around a bit. --- .../Microsoft.Android.Runtime.proj | 5 ++-- .../xaprepare/Steps/Step_GenerateFiles.cs | 1 - .../WorkloadManifest.in.json | 4 ++-- src/native-clr/CMakePresets.json.in | 1 - src/native-clr/native-clr.csproj | 2 +- src/native-clr/native-clr.targets | 23 ++++--------------- src/native/native-mono.csproj | 3 +-- src/native/native.targets | 2 +- 8 files changed, 12 insertions(+), 29 deletions(-) diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index fa1aec12a45..a8963b51859 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -45,8 +45,9 @@ projects that use the Microsoft.Android framework in .NET 6+. Condition=" '$(AndroidRuntime)' == 'NativeAOT' " /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\Mono.Android.Export.dll" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so" /> + + + <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.debug.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.debug.so" /> <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.release.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.release.so" /> <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-debug-app-helper.so" /> diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs index e7a48b4e4c0..ddf440117bb 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -118,7 +118,6 @@ GeneratedFile GetCmakePresetsCommon (Context context, string sourcesDir) { "@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 () }, diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json b/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json index 50fc5a22030..a61053ed7d1 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json @@ -15,8 +15,8 @@ ], "platforms": [ "win-x64", "win-arm64", "linux-x64", "linux-arm64", "osx-x64", "osx-arm64" ], "extends" : [ - "microsoft-net-runtime-android-net9", - "microsoft-net-runtime-android-aot-net9", + "microsoft-net-runtime-android-net8", + "microsoft-net-runtime-android-aot-net8", "microsoft-net-runtime-android", "microsoft-net-runtime-android-aot" ] diff --git a/src/native-clr/CMakePresets.json.in b/src/native-clr/CMakePresets.json.in index 33c910f6845..5544b1252b0 100644 --- a/src/native-clr/CMakePresets.json.in +++ b/src/native-clr/CMakePresets.json.in @@ -21,7 +21,6 @@ "ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES": "ON", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", "CMAKE_MAKE_PROGRAM": "@NinjaPath@", - "OUTPUT_PATH": "@OutputPath@", "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", "XA_BUILD_CONFIGURATION": "@XA_BUILD_CONFIGURATION@" } diff --git a/src/native-clr/native-clr.csproj b/src/native-clr/native-clr.csproj index 43244cd9e8c..59d9457516f 100644 --- a/src/native-clr/native-clr.csproj +++ b/src/native-clr/native-clr.csproj @@ -11,7 +11,7 @@ - $(MicrosoftAndroidSdkOutDir)lib\ + $(MicrosoftAndroidSdkOutDir)lib\coreclr\ diff --git a/src/native-clr/native-clr.targets b/src/native-clr/native-clr.targets index 6b5e9260382..b9d668a740e 100644 --- a/src/native-clr/native-clr.targets +++ b/src/native-clr/native-clr.targets @@ -38,7 +38,7 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - <_CmakeAndroidFlags>$(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" @@ -129,27 +129,12 @@ - <_ArmRuntimePackFiles Include="$(OutputPath)\android-arm\*.*" /> - <_Arm64RuntimePackFiles Include="$(OutputPath)\android-arm64\*.*" /> - <_x86RuntimePackFiles Include="$(OutputPath)\android-x86\*.*" /> - <_x64RuntimePackFiles Include="$(OutputPath)\android-x64\*.*" /> + <_RuntimePackFiles Include="$(OutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)\*" AndroidRID="%(AndroidSupportedTargetJitAbi.AndroidRID)" AndroidRuntime="CoreCLR" /> - - - diff --git a/src/native/native-mono.csproj b/src/native/native-mono.csproj index 5800dd911d1..f9f5aeb7f70 100644 --- a/src/native/native-mono.csproj +++ b/src/native/native-mono.csproj @@ -11,8 +11,7 @@ - $(NativeRuntimeOutputRootDir)mono\ - MonoVM + $(MicrosoftAndroidSdkOutDir)lib\mono\ diff --git a/src/native/native.targets b/src/native/native.targets index 6b997259f4a..1a9ad1c94aa 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -113,7 +113,7 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" From 38f0b6d7007971aea5be4278ece22ce352372f85 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 13 Jan 2025 16:17:41 +0100 Subject: [PATCH 053/143] New src/native layout --- Xamarin.Android.sln | 12 +- .../xaprepare/Steps/Step_GenerateFiles.cs | 1 + src/native-clr/.gitignore | 2 - src/native-clr/include/constants.hh | 119 --- .../include/runtime-base/android-system.hh | 104 -- src/native-clr/include/runtime-base/logger.hh | 63 -- .../include/runtime-base/monodroid-state.hh | 21 - .../runtime-base/startup-aware-lock.hh | 40 - .../include/runtime-base/timing-internal.hh | 466 --------- src/native-clr/include/runtime-base/timing.hh | 149 --- src/native-clr/include/runtime-base/util.hh | 123 --- src/native-clr/include/shared/log_types.hh | 118 --- src/native-clr/include/startup/zip.hh | 31 - src/native-clr/include/xamarin-app.hh | 380 ------- src/native-clr/libnet-android.map.txt | 12 - src/native-clr/runtime-base/CMakeLists.txt | 51 - src/native-clr/runtime-base/android-system.cc | 330 ------ src/native-clr/runtime-base/logger.cc | 214 ---- .../runtime-base/timing-internal.cc | 83 -- src/native-clr/runtime-base/timing.cc | 14 - src/native-clr/runtime-base/util.cc | 82 -- src/native-clr/shared/CMakeLists.txt | 50 - src/native-clr/shared/helpers.cc | 46 - src/native-clr/shared/log_functions.cc | 131 --- src/native-clr/startup/CMakeLists.txt | 53 - src/native-clr/startup/zip.cc | 3 - .../xamarin-app-stub/CMakeLists.txt | 54 - .../xamarin-app-stub/application_dso_stub.cc | 298 ------ src/native/.gitignore | 3 - src/native/CMakeLists.txt | 28 +- src/native/CMakePresets.json.in | 1 + .../clr}/host/CMakeLists.txt | 0 .../clr}/host/host-jni.cc | 0 src/{native-clr => native/clr}/host/host.cc | 0 src/native/clr/include/constants.hh | 34 +- .../clr}/include/host/host-jni.hh | 0 .../clr}/include/host/host.hh | 0 .../include/runtime-base/android-system.hh | 51 +- .../clr}/include/runtime-base/jni-wrappers.hh | 0 src/native/clr/include/runtime-base/logger.hh | 2 +- .../clr}/include/runtime-base/strings.hh | 0 .../include/runtime-base/timing-internal.hh | 2 +- src/native/clr/include/runtime-base/util.hh | 117 +-- .../clr}/include/shared/cpp-util.hh | 0 .../clr}/include/shared/helpers.hh | 0 .../clr}/include/shared/log_level.hh | 0 src/native/clr/include/shared/log_types.hh | 2 +- .../clr}/include/shared/xxhash.hh | 0 src/native/clr/include/startup/zip.hh | 102 +- src/native/clr/include/xamarin-app.hh | 23 +- src/native/clr/runtime-base/CMakeLists.txt | 61 +- src/native/clr/runtime-base/android-system.cc | 165 +-- src/native/clr/shared/CMakeLists.txt | 4 +- src/native/clr/shared/helpers.cc | 2 +- src/native/clr/startup/CMakeLists.txt | 6 +- src/native/clr/startup/zip.cc | 485 --------- .../clr/xamarin-app-stub/CMakeLists.txt | 4 +- .../xamarin-app-stub/application_dso_stub.cc | 68 +- .../monolibmono-android.map.txt} | 0 src/native/mono/runtime-base/jni-wrappers.hh | 209 ++++ src/native/mono/runtime-base/search.hh | 60 ++ src/native/mono/runtime-base/strings.hh | 964 ++++++++++++++++++ src/native/mono/shared/helpers.hh | 106 ++ src/native/mono/shared/log_types.hh | 2 +- src/native/mono/shared/xxhash.hh | 194 ++++ src/native/native-clr.csproj | 23 + src/native/native-mono.csproj | 3 +- src/native/native.targets | 107 +- 68 files changed, 1671 insertions(+), 4207 deletions(-) delete mode 100644 src/native-clr/.gitignore delete mode 100644 src/native-clr/include/constants.hh delete mode 100644 src/native-clr/include/runtime-base/android-system.hh delete mode 100644 src/native-clr/include/runtime-base/logger.hh delete mode 100644 src/native-clr/include/runtime-base/monodroid-state.hh delete mode 100644 src/native-clr/include/runtime-base/startup-aware-lock.hh delete mode 100644 src/native-clr/include/runtime-base/timing-internal.hh delete mode 100644 src/native-clr/include/runtime-base/timing.hh delete mode 100644 src/native-clr/include/runtime-base/util.hh delete mode 100644 src/native-clr/include/shared/log_types.hh delete mode 100644 src/native-clr/include/startup/zip.hh delete mode 100644 src/native-clr/include/xamarin-app.hh delete mode 100644 src/native-clr/libnet-android.map.txt delete mode 100644 src/native-clr/runtime-base/CMakeLists.txt delete mode 100644 src/native-clr/runtime-base/android-system.cc delete mode 100644 src/native-clr/runtime-base/logger.cc delete mode 100644 src/native-clr/runtime-base/timing-internal.cc delete mode 100644 src/native-clr/runtime-base/timing.cc delete mode 100644 src/native-clr/runtime-base/util.cc delete mode 100644 src/native-clr/shared/CMakeLists.txt delete mode 100644 src/native-clr/shared/helpers.cc delete mode 100644 src/native-clr/shared/log_functions.cc delete mode 100644 src/native-clr/startup/CMakeLists.txt delete mode 100644 src/native-clr/startup/zip.cc delete mode 100644 src/native-clr/xamarin-app-stub/CMakeLists.txt delete mode 100644 src/native-clr/xamarin-app-stub/application_dso_stub.cc delete mode 100644 src/native/.gitignore rename src/{native-clr => native/clr}/host/CMakeLists.txt (100%) rename src/{native-clr => native/clr}/host/host-jni.cc (100%) rename src/{native-clr => native/clr}/host/host.cc (100%) rename src/{native-clr => native/clr}/include/host/host-jni.hh (100%) rename src/{native-clr => native/clr}/include/host/host.hh (100%) rename src/{native-clr => native/clr}/include/runtime-base/jni-wrappers.hh (100%) rename src/{native-clr => native/clr}/include/runtime-base/strings.hh (100%) rename src/{native-clr => native/clr}/include/shared/cpp-util.hh (100%) rename src/{native-clr => native/clr}/include/shared/helpers.hh (100%) rename src/{native-clr => native/clr}/include/shared/log_level.hh (100%) rename src/{native-clr => native/clr}/include/shared/xxhash.hh (100%) rename src/native/{libmono-android.map.txt => mono/monolibmono-android.map.txt} (100%) create mode 100644 src/native/mono/runtime-base/jni-wrappers.hh create mode 100644 src/native/mono/runtime-base/search.hh create mode 100644 src/native/mono/runtime-base/strings.hh create mode 100644 src/native/mono/shared/helpers.hh create mode 100644 src/native/mono/shared/xxhash.hh create mode 100644 src/native/native-clr.csproj diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index 936ba23b285..faccbca0dbd 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -125,7 +125,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Sdk.Analy EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proguard-android", "src\proguard-android\proguard-android.csproj", "{5FD0133B-69E5-4474-9B67-9FD1D0150C70}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "native-clr", "src\native-clr\native-clr.csproj", "{AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "native-clr", "src\native\native-clr.csproj", "{39F49484-872A-489D-8E6B-3BC532DD571D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -349,10 +349,10 @@ Global {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Debug|AnyCPU.Build.0 = Debug|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.ActiveCfg = Release|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.Build.0 = Release|Any CPU - {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU - {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Debug|AnyCPU.Build.0 = Debug|Any CPU - {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Release|AnyCPU.ActiveCfg = Release|Any CPU - {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B}.Release|AnyCPU.Build.0 = Release|Any CPU + {39F49484-872A-489D-8E6B-3BC532DD571D}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU + {39F49484-872A-489D-8E6B-3BC532DD571D}.Debug|AnyCPU.Build.0 = Debug|Any CPU + {39F49484-872A-489D-8E6B-3BC532DD571D}.Release|AnyCPU.ActiveCfg = Release|Any CPU + {39F49484-872A-489D-8E6B-3BC532DD571D}.Release|AnyCPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -412,7 +412,7 @@ Global {A39B6D7C-6616-40D6-8AE4-C6CEE93D2708} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {5E806C9F-1B67-4B6B-A6AB-258834250DBB} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} {5FD0133B-69E5-4474-9B67-9FD1D0150C70} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} - {AD6DF548-2BC0-44E2-9ADC-28B4A23A1F5B} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} + {39F49484-872A-489D-8E6B-3BC532DD571D} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6} diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs index ddf440117bb..e7a48b4e4c0 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -118,6 +118,7 @@ GeneratedFile GetCmakePresetsCommon (Context context, string sourcesDir) { "@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 () }, diff --git a/src/native-clr/.gitignore b/src/native-clr/.gitignore deleted file mode 100644 index 34d21e62347..00000000000 --- a/src/native-clr/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -CMakeUserPresets.json -CMakePresets.json diff --git a/src/native-clr/include/constants.hh b/src/native-clr/include/constants.hh deleted file mode 100644 index f024da0a6eb..00000000000 --- a/src/native-clr/include/constants.hh +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "shared/cpp-util.hh" - -namespace xamarin::android { - class Constants - { -#if INTPTR_MAX == INT64_MAX - static inline constexpr std::string_view BITNESS { "64bit" }; -#else - static inline constexpr std::string_view BITNESS { "32bit" }; -#endif - - public: -#if defined(RELEASE) - static constexpr bool IsReleaseBuild = true; - static constexpr bool IsDebugBuild = false; -#else - static constexpr bool IsReleaseBuild = false; - static constexpr bool IsDebugBuild = true; -#endif - static constexpr std::string_view MANGLED_ASSEMBLY_NAME_EXT { ".so" }; - - private: - static constexpr std::string_view RUNTIME_CONFIG_BLOB_BASE_NAME { "libarc.bin" }; - static constexpr size_t runtime_config_blob_name_size = calc_size (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); - static constexpr auto RUNTIME_CONFIG_BLOB_NAME_ARRAY = concat_string_views (RUNTIME_CONFIG_BLOB_BASE_NAME, MANGLED_ASSEMBLY_NAME_EXT); - - public: - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view RUNTIME_CONFIG_BLOB_NAME { RUNTIME_CONFIG_BLOB_NAME_ARRAY.data () }; - 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" }; - - 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*" }; - -#if defined(__arm__) - static constexpr std::string_view android_abi { "armeabi_v7a" }; - static constexpr std::string_view android_lib_abi { "armeabi-v7a" }; - static constexpr std::string_view runtime_identifier { "android-arm" }; -#elif defined(__aarch64__) - static constexpr std::string_view android_abi { "arm64_v8a" }; - static constexpr std::string_view android_lib_abi { "arm64-v8a" }; - static constexpr std::string_view runtime_identifier { "android-arm64" }; -#elif defined(__x86_64__) - static constexpr std::string_view android_abi { "x86_64" }; - static constexpr std::string_view android_lib_abi { "x86_64" }; - static constexpr std::string_view runtime_identifier { "android-x64" }; -#elif defined(__i386__) - static constexpr std::string_view android_abi { "x86" }; - static constexpr std::string_view android_lib_abi { "x86" }; - static constexpr std::string_view runtime_identifier { "android-x86" }; -#endif - - static constexpr std::string_view split_config_prefix { "/split_config." }; - static constexpr std::string_view split_config_extension { ".apk" }; - - static constexpr size_t split_config_abi_apk_name_size = calc_size (split_config_prefix, android_abi, split_config_extension); - static constexpr auto split_config_abi_apk_name = concat_string_views (split_config_prefix, android_abi, split_config_extension); - - // - // Indexes must match these of trhe `appDirs` array in src/java-runtime/mono/android/MonoPackageManager.java - // - static constexpr size_t APP_DIRS_FILES_DIR_INDEX = 0uz; - static constexpr size_t APP_DIRS_CACHE_DIR_INDEX = 1uz; - static constexpr size_t APP_DIRS_DATA_DIR_INDEX = 2uz; - - static inline constexpr size_t PROPERTY_VALUE_BUFFER_LEN = PROP_VALUE_MAX + 1uz; - - // 64-bit unsigned or 64-bit signed with sign - static constexpr size_t MAX_INTEGER_DIGIT_COUNT_BASE10 = 21uz; - static constexpr size_t INTEGER_BASE10_BUFFER_SIZE = MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz; - - // Documented in NDK's comments - static constexpr size_t MAX_LOGCAT_MESSAGE_LENGTH = 1023uz; - - // PATH_MAX is always 4096 on Linux, but for our purposes it's most likely too much and since - // we use this value to allocate stack variables mostly, let's downsize it a bit to what the - // _XOPEN_PATH_MAX is set to - static constexpr size_t SENSIBLE_PATH_MAX = 1024uz; - - static constexpr int DEFAULT_DIRECTORY_MODE = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - -#if defined (DEBUG) - static constexpr std::string_view OVERRIDE_ENVIRONMENT_FILE_NAME { "environment" }; - static constexpr uint32_t OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE = 22; -#endif - }; -} diff --git a/src/native-clr/include/runtime-base/android-system.hh b/src/native-clr/include/runtime-base/android-system.hh deleted file mode 100644 index cf21b566dca..00000000000 --- a/src/native-clr/include/runtime-base/android-system.hh +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "../constants.hh" -#include "../shared/log_types.hh" -#include "jni-wrappers.hh" -#include "strings.hh" -#include "util.hh" - -struct BundledProperty; - -namespace xamarin::android { - class AndroidSystem - { - public: - static auto get_max_gref_count () noexcept -> long - { - return max_gref_count; - } - - static void init_max_gref_count () noexcept - { - max_gref_count = get_max_gref_count_from_system (); - } - - static void set_running_in_emulator (bool yesno) noexcept - { - running_in_emulator = yesno; - } - - static auto get_primary_override_dir () noexcept -> std::string const& - { - return primary_override_dir; - } - - static void set_primary_override_dir (jstring_wrapper& home) noexcept - { - primary_override_dir = determine_primary_override_dir (home); - } - - static void create_update_dir (std::string const& override_dir) noexcept - { - if constexpr (Constants::IsReleaseBuild) { - /* - * Don't create .__override__ on Release builds, because Google requires - * that pre-loaded apps not create world-writable directories. - * - * However, if any logging is enabled (which should _not_ happen with - * pre-loaded apps!), we need the .__override__ directory... - */ - dynamic_local_string value; - if (log_categories == 0 && monodroid_get_system_property (Constants::DEBUG_MONO_PROFILE_PROPERTY, value) == 0) [[likely]] { - return; - } - } - - Util::create_public_directory (override_dir); - log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); - } - - static auto monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int; - static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; - static void setup_environment () noexcept; - - private: - static auto lookup_system_property (std::string_view const &name, size_t &value_len) noexcept -> const char*; - static auto monodroid__system_property_get (std::string_view const&, char *sp_value, size_t sp_value_len) noexcept -> int; - static auto get_max_gref_count_from_system () noexcept -> long; -#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 (dynamic_local_string const& path) noexcept; -#endif - - static void set_embedded_dso_mode_enabled (bool yesno) noexcept - { - embedded_dso_mode_enabled = yesno; - } - - static auto determine_primary_override_dir (jstring_wrapper &home) noexcept -> std::string - { - dynamic_local_string name { home.get_cstr () }; - name.append ("/") - .append (Constants::OVERRIDE_DIRECTORY_NAME) - .append ("/") - .append (Constants::android_lib_abi); - - return {name.get (), name.length ()}; - } - - private: - static inline long max_gref_count = 0; - static inline bool running_in_emulator = false; - static inline bool embedded_dso_mode_enabled = false; - static inline std::string primary_override_dir; - -#if defined (DEBUG) - static inline std::unordered_map bundled_properties; -#endif - }; -} diff --git a/src/native-clr/include/runtime-base/logger.hh b/src/native-clr/include/runtime-base/logger.hh deleted file mode 100644 index 45c9e2449bd..00000000000 --- a/src/native-clr/include/runtime-base/logger.hh +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include "strings.hh" - -namespace xamarin::android { - class Logger - { - public: - static void init_logging_categories () noexcept; - static void init_reference_logging (std::string_view const& override_dir) noexcept; - - static auto log_timing_categories () noexcept -> LogTimingCategories - { - return _log_timing_categories; - } - - static void set_gc_spew_enabled (bool yesno) noexcept - { - _gc_spew_enabled = yesno; - } - - static auto gc_spew_enabled () noexcept -> bool - { - return _gc_spew_enabled; - } - - static auto gref_log () -> FILE* - { - return _gref_log; - } - - static auto lref_log () -> FILE* - { - return _lref_log; - } - - static auto gref_to_logcat () -> bool - { - return _gref_to_logcat; - } - - static auto lref_to_logcat () -> bool - { - return _lref_to_logcat; - } - - private: - static bool set_category (std::string_view const& name, string_segment& arg, unsigned int entry, bool arg_starts_with_name = false) noexcept; - - private: - static inline LogTimingCategories _log_timing_categories; - static inline bool _gc_spew_enabled = false; - static inline FILE *_gref_log = nullptr; - static inline FILE *_lref_log = nullptr; - static inline bool _gref_to_logcat = false; - static inline bool _lref_to_logcat = false; - }; -} diff --git a/src/native-clr/include/runtime-base/monodroid-state.hh b/src/native-clr/include/runtime-base/monodroid-state.hh deleted file mode 100644 index 283040d4992..00000000000 --- a/src/native-clr/include/runtime-base/monodroid-state.hh +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -namespace xamarin::android -{ - class MonodroidState - { - public: - static auto is_startup_in_progress () noexcept -> bool - { - return startup_in_progress; - } - - static void mark_startup_done () noexcept - { - startup_in_progress = false; - } - - private: - inline static bool startup_in_progress = true; - }; -} diff --git a/src/native-clr/include/runtime-base/startup-aware-lock.hh b/src/native-clr/include/runtime-base/startup-aware-lock.hh deleted file mode 100644 index 8b869151b61..00000000000 --- a/src/native-clr/include/runtime-base/startup-aware-lock.hh +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -#include "monodroid-state.hh" - -namespace xamarin::android -{ - class StartupAwareLock final - { - public: - explicit StartupAwareLock (std::mutex &m) - : lock (m) - { - if (MonodroidState::is_startup_in_progress ()) { - // During startup we run without threads, do nothing - return; - } - - lock.lock (); - } - - ~StartupAwareLock () - { - if (MonodroidState::is_startup_in_progress ()) { - return; - } - - lock.unlock (); - } - - StartupAwareLock (StartupAwareLock const&) = delete; - StartupAwareLock (StartupAwareLock const&&) = delete; - - StartupAwareLock& operator= (StartupAwareLock const&) = delete; - - private: - std::mutex& lock; - }; -} diff --git a/src/native-clr/include/runtime-base/timing-internal.hh b/src/native-clr/include/runtime-base/timing-internal.hh deleted file mode 100644 index d9c29ca53a9..00000000000 --- a/src/native-clr/include/runtime-base/timing-internal.hh +++ /dev/null @@ -1,466 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include "startup-aware-lock.hh" -#include "strings.hh" -#include "util.hh" -#include "../constants.hh" -#include "monodroid-state.hh" - -namespace xamarin::android { - // bionic should use `time_t` in the timespec struct, but it uses `long` instead - using time_type = long; - - // Events should never change their assigned values and no values should be reused. - // Values are used by the test runner to determine what measurement was taken. - // - // At the same time, the list should be kept sorted alphabetically for easier reading - - // values therefore might be out of order, but always unique. - enum class TimingEventKind - { - AssemblyDecompression = 0, - AssemblyLoad = 1, - AssemblyPreload = 2, - DebugStart = 3, - Init = 4, - JavaToManaged = 5, - ManagedToJava = 6, - MonoRuntimeInit = 7, - NativeToManagedTransition = 8, - RuntimeConfigBlob = 9, - RuntimeRegister = 10, - TotalRuntimeInit = 11, - Unspecified = 12, - }; - - struct TimingEventPoint - { - time_t sec; - uint64_t ns; - }; - - struct TimingInterval - { - time_t sec; - uint32_t ms; - uint32_t ns; - }; - - struct TimingEvent - { - bool before_managed; - TimingEventPoint start; - TimingEventPoint end; - TimingEventKind kind; - std::unique_ptr more_info; - }; - - template - concept TimingPointType = requires (T a) { - { a.sec } -> std::same_as; - { a.ns } -> std::same_as; - }; - - template - concept TimingIntervalType = requires (T a) { - { a.sec } -> std::same_as; - { a.ms } -> std::same_as; - { a.ns } -> std::same_as; - }; - - class FastTiming final - { - // Number of TimingEvent entries in the event vector allocated at the - // time of class instantiation. It's an arbitrary value, but it should - // be large enough to not require any dynamic reallocation of memory at - // the run time. - static constexpr size_t INITIAL_EVENT_VECTOR_SIZE = 4096uz; - static constexpr uint32_t ns_in_millisecond = 1000000u; - static constexpr uint32_t ms_in_second = 1000u; - static constexpr uint32_t ns_in_second = ms_in_second * ns_in_millisecond; - - protected: - FastTiming () noexcept - { - events.reserve (INITIAL_EVENT_VECTOR_SIZE); - } - - public: - [[gnu::always_inline]] - static auto enabled () noexcept -> bool - { - return is_enabled; - } - - [[gnu::always_inline]] - static auto is_bare_mode () noexcept -> bool - { - return - (Logger::log_timing_categories() & LogTimingCategories::Bare) == LogTimingCategories::Bare || - (Logger::log_timing_categories() & LogTimingCategories::FastBare) == LogTimingCategories::FastBare; - } - - [[gnu::always_inline]] - static void initialize (bool log_immediately) noexcept - { - if (!Util::should_log (LOG_TIMING)) [[likely]] { - return; - } - - mark (init_time.start); - really_initialize (log_immediately); - mark (init_time.end); - - init_time.before_managed = true; - init_time.kind = TimingEventKind::Init; - - if (!immediate_logging) { - return; - } - - log (init_time, false /* skip_log_if_more_info_missing */); - } - - // std::vector isn't used in a conventional manner here. We treat it as if it was a standard array and we - // don't take advantage of any emplacement functionality, merely using vector's ability to resize itself when - // needed. The reason for this is speed - we can atomically increase index into the array and relatively - // quickly check whether it's within the boundaries. We can then safely use thus indexed element without - // worrying about concurrency. Emplacing a new element in the vector would require holding the mutex, something - // that's fairly costly and has unpredictable effect on time spent acquiring and holding the lock (the OS can - // preempt us at this point) - [[gnu::always_inline]] - auto start_event (TimingEventKind kind = TimingEventKind::Unspecified) noexcept -> size_t - { - size_t index = next_event_index.fetch_add (1); - - if (index >= events.capacity ()) [[unlikely]] { - StartupAwareLock lock (event_vector_realloc_mutex); - if (index >= events.size ()) { // don't increase unnecessarily, if another thread has already done that - // Double the vector size. We should, in theory, check for integer overflow here, but it's more - // likely we'll run out of memory way, way, way before that happens - size_t old_size = events.capacity (); - events.reserve (old_size << 1); - log_warn (LOG_TIMING, "Reallocated timing event buffer from {} to {}", old_size, events.size ()); - } - } - - TimingEvent &ev = events[index]; - mark (ev.start); - ev.kind = kind; - ev.before_managed = MonodroidState::is_startup_in_progress (); - ev.more_info = nullptr; - - return index; - } - - [[gnu::always_inline]] - void end_event (size_t event_index, bool uses_more_info = false) noexcept - { - if (!is_valid_event_index (event_index, __PRETTY_FUNCTION__)) [[unlikely]] { - return; - } - - mark (events[event_index].end); - log (events[event_index], uses_more_info /* skip_log_if_more_info_missing */); - } - - template - [[gnu::always_inline]] - void add_more_info (size_t event_index, string_base const& str) noexcept - { - if (!is_valid_event_index (event_index, __PRETTY_FUNCTION__)) [[unlikely]] { - return; - } - - events[event_index].more_info = std::make_unique (str.get (), str.length ()); - log (events[event_index], false /* skip_log_if_more_info_missing */); - } - - [[gnu::always_inline]] - void add_more_info (size_t event_index, const char* str) noexcept - { - if (!is_valid_event_index (event_index, __PRETTY_FUNCTION__)) [[unlikely]] { - return; - } - - events[event_index].more_info = std::make_unique (str); - log (events[event_index], false /* skip_log_if_more_info_missing */); - } - - [[gnu::always_inline]] - static void get_time (time_t &seconds_out, uint64_t& ns_out) noexcept - { - int ret; - timespec tv_ctm; - - ret = clock_gettime (CLOCK_MONOTONIC, &tv_ctm); - ns_out = ret == 0 ? static_cast(tv_ctm.tv_nsec) : 0; - seconds_out = ret == 0 ? tv_ctm.tv_sec : 0; - } - - template [[gnu::always_inline]] - static void calculate_interval (P const& start, P const& end, I &result) noexcept - { - uint64_t nsec; - if (end.ns < start.ns) { - result.sec = end.sec - start.sec - 1; - if (result.sec < 0) { - result.sec = 0; - } - nsec = 1000000000ULL + end.ns - start.ns; - } else { - result.sec = end.sec - start.sec; - nsec = end.ns - start.ns; - } - - result.ms = static_cast(nsec / ns_in_millisecond); - if (result.ms >= ms_in_second) { - result.sec += result.ms / ms_in_second; - result.ms = result.ms % ms_in_second; - } - - result.ns = static_cast(nsec % ns_in_millisecond); - } - - template [[gnu::always_inline]] - static void calculate_interval (P const& start, P const& end, I &result, uint64_t& total_ns) noexcept - { - calculate_interval (start, end, result); - total_ns = - (static_cast(result.sec) * static_cast(ns_in_second)) + - (static_cast(result.ms) * static_cast(ns_in_millisecond)) + - static_cast(result.ns); - } - - void dump () noexcept; - - private: - static void really_initialize (bool log_immediately) noexcept; - static void* timing_signal_thread (void *arg) noexcept; - - [[gnu::always_inline]] - static void mark (TimingEventPoint &point) noexcept - { - get_time (point.sec, point.ns); - } - - [[gnu::always_inline]] - auto is_valid_event_index (size_t index, const char *method_name) noexcept -> bool - { - if (index >= events.capacity ()) [[unlikely]] { - log_warn (LOG_TIMING, "Invalid event index passed to method '{}'", method_name); - return false; - } - - return true; - } - - template [[gnu::always_inline]] - static void append_event_kind_description (TimingEventKind kind, dynamic_local_string& message) noexcept - { - switch (kind) { - case TimingEventKind::AssemblyDecompression: { - constexpr char desc[] = "LZ4 decompression time for "; - message.append (desc); - return; - } - - case TimingEventKind::AssemblyLoad: { - constexpr char desc[] = "Assembly load"; - message.append (desc); - return; - } - - case TimingEventKind::AssemblyPreload: { - constexpr char desc[] = "Finished preloading, number of loaded assemblies: "; - message.append (desc); - return; - } - - case TimingEventKind::DebugStart: { - constexpr char desc[] = "Debug::start_debugging_and_profiling: end"; - message.append (desc); - return; - } - - case TimingEventKind::Init: { - constexpr char desc[] = "XATiming: init time"; - message.append (desc); - return; - } - - case TimingEventKind::JavaToManaged: { - constexpr char desc[] = "Typemap.java_to_managed: end, total time"; - message.append (desc); - return; - } - - case TimingEventKind::ManagedToJava: { - constexpr char desc[] = "Typemap.managed_to_java: end, total time"; - message.append (desc); - return; - } - - case TimingEventKind::MonoRuntimeInit: { - constexpr char desc[] = "Runtime.init: Mono runtime init"; - message.append (desc); - return; - } - - case TimingEventKind::NativeToManagedTransition: { - constexpr char desc[] = "Runtime.init: end native-to-managed transition"; - message.append (desc); - return; - } - - case TimingEventKind::RuntimeConfigBlob: { - constexpr char desc[] = "Register runtimeconfig binary blob"; - message.append (desc); - return; - } - - case TimingEventKind::RuntimeRegister: { - constexpr char desc[] = "Runtime.register: end time. Registered type: "; - message.append (desc); - return; - } - - case TimingEventKind::TotalRuntimeInit: { - constexpr char desc[] = "Runtime.init: end, total time"; - message.append (desc); - return; - } - - default: { - constexpr char desc[] = "Unknown timing event"; - message.append (desc); - return; - } - } - } - - // - // Message format is as follows: [STAGE/EVENT] ; elapsed s:ms::ns - // - // STAGE is one of: - // 0 - native init (before managed code runs) - // 1 - managed code enabled - // 2 - events summary (see the `dump()` function) - // - // EVENT is one of: - // for stages 0 and 1, it's the value of the TimingEventKind member - // for stage 2 see the `dump()` function - // - // The [STAGE/EVENT] format is meant to help the test runner application, so that it can parse logcat without - // having to be kept in sync with the actual wording used for the event message. - // - template [[gnu::always_inline]] - static void format_and_log (TimingEvent const& event, TimingInterval const& interval, dynamic_local_string& message, bool indent = false) noexcept - { - constexpr char INDENT[] = " "; - constexpr char NATIVE_INIT_TAG[] = "[0/"; - constexpr char MANAGED_TAG[] = "[1/"; - - message.clear (); - if (indent) { - message.append (INDENT); - } - - if (event.before_managed) { - message.append (NATIVE_INIT_TAG); - } else { - message.append (MANAGED_TAG); - } - - message.append (static_cast(event.kind)); - message.append ("] "); - - append_event_kind_description (event.kind, message); - if (event.more_info && !event.more_info->empty ()) { - message.append (event.more_info->c_str (), event.more_info->length ()); - } - - constexpr char COLON[] = ":"; - constexpr char TWO_COLONS[] = "::"; - - message.append ("; elapsed: "); - message.append (static_cast(interval.sec)); - message.append (COLON); - message.append (interval.ms); - message.append (TWO_COLONS); - message.append (interval.ns); - - log_write (LOG_TIMING, LogLevel::Info, message.get ()); - } - - template [[gnu::always_inline]] - static void format_and_log (TimingEvent const& event, dynamic_local_string& message, uint64_t& total_ns, bool indent = false) noexcept - { - TimingInterval interval; - calculate_interval (event.start, event.end, interval, total_ns); - format_and_log (event, interval, message, indent); - } - - [[gnu::always_inline]] - static void format_and_log (TimingEvent const& event) noexcept - { - TimingInterval interval; - calculate_interval (event.start, event.end, interval); - - // `message` isn't used here, it is passed to `format_and_log` so that the `dump()` function can - // be slightly more efficient when dumping the event buffer. - dynamic_local_string message; - format_and_log (event, interval, message); - } - - [[gnu::always_inline]] - static void log (TimingEvent const& event, bool skip_log_if_more_info_missing) noexcept - { - if (!immediate_logging) { - return; - } - - if (skip_log_if_more_info_missing && (!event.more_info || event.more_info->empty ())) { - return; - } - - format_and_log (event); - } - - [[gnu::always_inline]] - static void ns_to_time (uint64_t total_ns, uint32_t &sec, uint32_t &ms, uint32_t &ns) noexcept - { - sec = static_cast(total_ns / ns_in_second); - if (sec > 0) { - total_ns = total_ns % 1000000000ULL; - } - - ms = static_cast(total_ns / ns_in_millisecond); - if (ms >= 1000) { - sec += ms / 1000; - ms = ms % 1000; - } - - ns = static_cast(total_ns % ns_in_millisecond); - } - - private: - std::atomic_size_t next_event_index = 0uz; - std::mutex event_vector_realloc_mutex; - std::vector events; - - static inline TimingEvent init_time{}; - static inline bool is_enabled = false; - static inline bool immediate_logging = false; - }; - - extern FastTiming *internal_timing; -} diff --git a/src/native-clr/include/runtime-base/timing.hh b/src/native-clr/include/runtime-base/timing.hh deleted file mode 100644 index 9baf105c4b1..00000000000 --- a/src/native-clr/include/runtime-base/timing.hh +++ /dev/null @@ -1,149 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "logger.hh" - -namespace xamarin::android -{ - struct timing_point - { - time_t sec = 0; - uint64_t ns = 0; - - void mark (); - - void reset () - { - sec = 0; - ns = 0; - } - }; - - struct timing_period - { - timing_point start; - timing_point end; - - void mark_start () - { - start.mark (); - } - - void mark_end () - { - end.mark (); - } - - void reset () - { - start.reset (); - end.reset (); - } - }; - - struct timing_diff - { - static constexpr uint32_t ms_in_nsec = 1000000ULL; - - time_t sec; - uint32_t ms; - uint32_t ns; - - timing_diff (const timing_period &period); - }; - - struct managed_timing_sequence - { - timing_period period; - bool in_use; - bool dynamic; - }; - - // This class is intended to be used by the managed code. It can be used by the native code as - // well, but the overhead it has (out of necessity) might not be desirable in native code. - class Timing - { - static inline constexpr std::string_view MESSAGE_FORMAT { "{}; elapsed: {}:{}::{}" }; - - public: - static constexpr size_t DEFAULT_POOL_SIZE = 16uz; - - public: - explicit Timing (size_t initial_pool_size = DEFAULT_POOL_SIZE) noexcept - : sequence_pool_size (initial_pool_size) - { - sequence_pool = new managed_timing_sequence [initial_pool_size] (); - } - - ~Timing () noexcept - { - delete[] sequence_pool; - } - - static void info (timing_period const &period, const char *message) noexcept - { - timing_diff diff (period); - - log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); - } - - static void warn (timing_period const &period, const char *message) noexcept - { - timing_diff diff (period); - - log_warn (LOG_TIMING, MESSAGE_FORMAT.data (), message == nullptr ? ""sv : message, diff.sec, diff.ms, diff.ns); - } - - managed_timing_sequence* get_available_sequence () noexcept - { - std::lock_guard lock (sequence_lock); - - managed_timing_sequence *ret; - for (size_t i = 0uz; i < sequence_pool_size; i++) { - if (sequence_pool[i].in_use) { - continue; - } - - ret = &sequence_pool[i]; - ret->in_use = true; - ret->dynamic = false; - - return ret; - } - - ret = new managed_timing_sequence (); - ret->dynamic = true; - - return ret; - } - - void release_sequence (managed_timing_sequence *sequence) - { - if (sequence == nullptr) - return; - - std::lock_guard lock (sequence_lock); - if (sequence->dynamic) { - sequence->period.reset (); - delete sequence; - return; - } - - sequence->in_use = false; - } - - private: - managed_timing_sequence *sequence_pool; - size_t sequence_pool_size; - std::mutex sequence_lock; - }; -} diff --git a/src/native-clr/include/runtime-base/util.hh b/src/native-clr/include/runtime-base/util.hh deleted file mode 100644 index 555b81e8db2..00000000000 --- a/src/native-clr/include/runtime-base/util.hh +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "../constants.hh" -#include "../shared/helpers.hh" -#include "jni-wrappers.hh" -#include "logger.hh" -#include "strings.hh" - -namespace xamarin::android { - namespace detail { - template - concept PathComponentString = requires { - std::same_as, char*> || - std::same_as, std::string_view> || - std::same_as, std::string>; - }; - - template - concept PathBuffer = requires { - std::derived_from, dynamic_local_storage> || - std::derived_from, static_local_storage>; - }; - } - - class Util - { - public: - static int create_directory (const char *pathname, mode_t mode); - static void create_public_directory (std::string_view const& dir); - static auto monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE*; - static void set_world_accessable (std::string_view const& path); - - static auto should_log (LogCategories category) noexcept -> bool - { - return (log_categories & category) != 0; - } - - static auto file_exists (const char *file) noexcept -> bool - { - if (file == nullptr) { - return false; - } - - struct stat s; - if (::stat (file, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG) { - return true; - } - return false; - } - - template - static auto file_exists (dynamic_local_string const& file) noexcept -> bool - { - if (file.empty ()) { - return false; - } - - return file_exists (file.get ()); - } - - static void set_environment_variable (std::string_view const& name, jstring_wrapper& value) noexcept - { - ::setenv (name.data (), value.get_cstr (), 1); - } - - static void set_environment_variable_for_directory (std::string_view const& name, jstring_wrapper& value, bool createDirectory, mode_t mode) noexcept - { - if (createDirectory) { - int rv = create_directory (value.get_cstr (), mode); - if (rv < 0 && errno != EEXIST) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}' for environment variable '{}'. {}", value.get_string_view (), name, strerror (errno)); - } - } - set_environment_variable (name, value); - } - - static void set_environment_variable_for_directory (const char *name, jstring_wrapper &value) noexcept - { - set_environment_variable_for_directory (name, value, true, Constants::DEFAULT_DIRECTORY_MODE); - } - - private: - // TODO: needs some work to accept mixed params of different accepted types - template TBuffer, detail::PathComponentString ...TPart> - static void path_combine_common (TBuffer& buf, TPart&&... parts) noexcept - { - buf.clear (); - - for (auto const& part : {parts...}) { - if (!buf.empty ()) { - buf.append ("/"sv); - } - - if constexpr (std::same_as, char*>) { - if (part != nullptr) { - buf.append_c (part); - } - } else { - buf.append (part); - } - } - } - - public: - template - static void path_combine (dynamic_local_string& buf, TParts&&... parts) noexcept - { - path_combine_common (buf, std::forward(parts)...); - } - - template - static void path_combine (static_local_string& buf, TParts&&... parts) noexcept - { - path_combine_common (buf, std::forward(parts)...); - } - }; -} diff --git a/src/native-clr/include/shared/log_types.hh b/src/native-clr/include/shared/log_types.hh deleted file mode 100644 index 656146ec203..00000000000 --- a/src/native-clr/include/shared/log_types.hh +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "java-interop-logger.h" -#include "log_level.hh" - -// We redeclare macros here -#if defined(log_debug) -#undef log_debug -#endif - -#if defined(log_info) -#undef log_info -#endif - -#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ - do { \ - if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ - } \ - } while (0) - -// -// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec -// - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -namespace xamarin::android { - // 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; - - [[gnu::always_inline]] - static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept - { - log_write (category, level, message.data ()); - } -} - -template [[gnu::always_inline]] -static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Debug, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Info, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); -} - -extern unsigned int log_categories; diff --git a/src/native-clr/include/startup/zip.hh b/src/native-clr/include/startup/zip.hh deleted file mode 100644 index 96afac707bd..00000000000 --- a/src/native-clr/include/startup/zip.hh +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include - -namespace xamarin::android { - class Zip - { - private: - static inline constexpr off_t ZIP_EOCD_LEN = 22; - static inline constexpr off_t ZIP_CENTRAL_LEN = 46; - static inline constexpr off_t ZIP_LOCAL_LEN = 30; - - static inline constexpr std::string_view ZIP_CENTRAL_MAGIC { "PK\1\2" }; - static inline constexpr std::string_view ZIP_LOCAL_MAGIC { "PK\3\4" }; - static inline constexpr std::string_view ZIP_EOCD_MAGIC { "PK\5\6" }; - - static constexpr std::string_view zip_path_separator { "/" }; - static constexpr std::string_view apk_lib_dir_name { "lib" }; - - static constexpr size_t assemblies_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); - static constexpr auto assemblies_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); - - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; - }; -} diff --git a/src/native-clr/include/xamarin-app.hh b/src/native-clr/include/xamarin-app.hh deleted file mode 100644 index bcf6287c233..00000000000 --- a/src/native-clr/include/xamarin-app.hh +++ /dev/null @@ -1,380 +0,0 @@ -// Dear Emacs, this is a -*- C++ -*- header -#pragma once - -#include - -#include - -#include "shared/xxhash.hh" - -static constexpr uint64_t FORMAT_TAG = 0x00035E6972616D58; // 'Xmari^XY' where XY is the format version -static constexpr uint32_t COMPRESSED_DATA_MAGIC = 0x5A4C4158; // 'XALZ', little-endian -static constexpr uint32_t ASSEMBLY_STORE_MAGIC = 0x41424158; // 'XABA', little-endian - -// The highest bit of assembly store version is a 64-bit ABI flag -#if INTPTR_MAX == INT64_MAX -static constexpr uint32_t ASSEMBLY_STORE_64BIT_FLAG = 0x80000000; -#else -static constexpr uint32_t ASSEMBLY_STORE_64BIT_FLAG = 0x00000000; -#endif - -// The second-to-last byte denotes the actual ABI -#if defined(__aarch64__) -static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00010000; -#elif defined(__arm__) -static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00020000; -#elif defined(__x86_64__) -static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00030000; -#elif defined(__i386__) -static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00040000; -#endif - -// Increase whenever an incompatible change is made to the assembly store format -static constexpr uint32_t ASSEMBLY_STORE_FORMAT_VERSION = 2 | ASSEMBLY_STORE_64BIT_FLAG | ASSEMBLY_STORE_ABI; - -static constexpr uint32_t MODULE_MAGIC_NAMES = 0x53544158; // 'XATS', little-endian -static constexpr uint32_t MODULE_INDEX_MAGIC = 0x49544158; // 'XATI', little-endian -static constexpr uint8_t MODULE_FORMAT_VERSION = 2; // Keep in sync with the value in src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs - -#if defined (DEBUG) -struct BinaryTypeMapHeader -{ - uint32_t magic; - uint32_t version; - uint32_t entry_count; - uint32_t java_name_width; - uint32_t managed_name_width; - uint32_t assembly_name_length; -}; - -struct TypeMapIndexHeader -{ - uint32_t magic; - uint32_t version; - uint32_t entry_count; - uint32_t module_file_name_width; -}; - -struct TypeMapEntry -{ - const char *from; - const char *to; -}; - -// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs -struct TypeMap -{ - uint32_t entry_count; - char *assembly_name; - uint8_t *data; - const TypeMapEntry *java_to_managed; - const TypeMapEntry *managed_to_java; -}; -#else -struct TypeMapModuleEntry -{ - uint32_t type_token_id; - uint32_t java_map_index; -}; - -struct TypeMapModule -{ - uint8_t module_uuid[16]; - uint32_t entry_count; - uint32_t duplicate_count; - TypeMapModuleEntry const *map; - TypeMapModuleEntry const *duplicate_map; - char const *assembly_name; - uint8_t *image; - uint32_t java_name_width; - uint8_t *java_map; -}; - -struct TypeMapJava -{ - uint32_t module_index; - uint32_t type_token_id; - uint32_t java_name_index; -}; -#endif - -struct CompressedAssemblyHeader -{ - uint32_t magic; // COMPRESSED_DATA_MAGIC - uint32_t descriptor_index; - uint32_t uncompressed_length; -}; - -struct CompressedAssemblyDescriptor -{ - uint32_t uncompressed_file_size; - bool loaded; - uint8_t *data; -}; - -struct CompressedAssemblies -{ - uint32_t count; - CompressedAssemblyDescriptor *descriptors; -}; - -struct XamarinAndroidBundledAssembly -{ - int32_t file_fd; - char *file_name; - uint32_t data_offset; - uint32_t data_size; - uint8_t *data; - uint32_t name_length; - char *name; -}; - -// -// Assembly store format -// -// Each target ABI/architecture has a single assembly store file, composed of the following parts: -// -// [HEADER] -// [INDEX] -// [ASSEMBLY_DESCRIPTORS] -// [ASSEMBLY DATA] -// -// Formats of the sections above are as follows: -// -// HEADER (fixed size) -// [MAGIC] uint; value: 0x41424158 -// [FORMAT_VERSION] uint; store format version number -// [ENTRY_COUNT] uint; number of entries in the store -// [INDEX_ENTRY_COUNT] uint; number of entries in the index -// [INDEX_SIZE] uint; index size in bytes -// -// INDEX (variable size, HEADER.ENTRY_COUNT*2 entries, for assembly names with and without the extension) -// [NAME_HASH] uint on 32-bit platforms, ulong on 64-bit platforms; xxhash of the assembly name -// [DESCRIPTOR_INDEX] uint; index into in-store assembly descriptor array -// -// ASSEMBLY_DESCRIPTORS (variable size, HEADER.ENTRY_COUNT entries), each entry formatted as follows: -// [MAPPING_INDEX] uint; index into a runtime array where assembly data pointers are stored -// [DATA_OFFSET] uint; offset from the beginning of the store to the start of assembly data -// [DATA_SIZE] uint; size of the stored assembly data -// [DEBUG_DATA_OFFSET] uint; offset from the beginning of the store to the start of assembly PDB data, 0 if absent -// [DEBUG_DATA_SIZE] uint; size of the stored assembly PDB data, 0 if absent -// [CONFIG_DATA_OFFSET] uint; offset from the beginning of the store to the start of assembly .config contents, 0 if absent -// [CONFIG_DATA_SIZE] uint; size of the stored assembly .config contents, 0 if absent -// -// ASSEMBLY_NAMES (variable size, HEADER.ENTRY_COUNT entries), each entry formatted as follows: -// [NAME_LENGTH] uint: length of assembly name -// [NAME] byte: UTF-8 bytes of assembly name, without the NUL terminator -// - -// -// The structures which are found in the store files must be packed to avoid problems when calculating offsets (runtime -// size of a structure can be different than the real data size) -// -struct [[gnu::packed]] AssemblyStoreHeader final -{ - uint32_t magic; - uint32_t version; - uint32_t entry_count; - uint32_t index_entry_count; - uint32_t index_size; // index size in bytes -}; - -struct [[gnu::packed]] AssemblyStoreIndexEntry final -{ - xamarin::android::hash_t name_hash; - uint32_t descriptor_index; -}; - -struct [[gnu::packed]] AssemblyStoreEntryDescriptor final -{ - uint32_t mapping_index; - - uint32_t data_offset; - uint32_t data_size; - - uint32_t debug_data_offset; - uint32_t debug_data_size; - - uint32_t config_data_offset; - uint32_t config_data_size; -}; - -struct AssemblyStoreRuntimeData final -{ - uint8_t *data_start; - uint32_t assembly_count; - uint32_t index_entry_count; - AssemblyStoreEntryDescriptor *assemblies; -}; - -struct AssemblyStoreSingleAssemblyRuntimeData final -{ - uint8_t *image_data; - uint8_t *debug_info_data; - uint8_t *config_data; - AssemblyStoreEntryDescriptor *descriptor; -}; - -// Keep in strict sync with: -// src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs -// src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs -struct ApplicationConfig -{ - bool uses_assembly_preload; - bool jni_add_native_method_registration_attribute_present; - bool have_runtime_config_blob; - bool marshal_methods_enabled; - bool ignore_split_configs; - uint32_t package_naming_policy; - uint32_t environment_variable_count; - uint32_t system_property_count; - uint32_t number_of_assemblies_in_apk; - uint32_t bundled_assembly_name_width; - uint32_t number_of_dso_cache_entries; - uint32_t number_of_aot_cache_entries; - uint32_t number_of_shared_libraries; - uint32_t android_runtime_jnienv_class_token; - uint32_t jnienv_initialize_method_token; - uint32_t jnienv_registerjninatives_method_token; - uint32_t jni_remapping_replacement_type_count; - uint32_t jni_remapping_replacement_method_index_entry_count; - const char *android_package_name; -}; - -struct DSOApkEntry -{ - uint64_t name_hash; - uint32_t offset; // offset into the APK - int32_t fd; // apk file descriptor -}; - -struct DSOCacheEntry -{ - uint64_t hash; - uint64_t real_name_hash; - bool ignore; - const char *name; - void *handle; -}; - -struct JniRemappingString -{ - const uint32_t length; - const char *str; -}; - -struct JniRemappingReplacementMethod -{ - const char *target_type; - const char *target_name; - // const char *target_signature; - // const int32_t param_count; - const bool is_static; -}; - -struct JniRemappingIndexMethodEntry -{ - const JniRemappingString name; - const JniRemappingString signature; - const JniRemappingReplacementMethod replacement; -}; - -struct JniRemappingIndexTypeEntry -{ - const JniRemappingString name; - const uint32_t method_count; - const JniRemappingIndexMethodEntry *methods; -}; - -struct JniRemappingTypeReplacementEntry -{ - const JniRemappingString name; - const char *replacement; -}; - -extern "C" { - [[gnu::visibility("default")]] extern const JniRemappingIndexTypeEntry jni_remapping_method_replacement_index[]; - [[gnu::visibility("default")]] extern const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[]; - - [[gnu::visibility("default")]] extern const uint64_t format_tag; - -#if defined (DEBUG) - [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs -#else - [[gnu::visibility("default")]] extern const uint32_t map_module_count; - [[gnu::visibility("default")]] extern const uint32_t java_type_count; - [[gnu::visibility("default")]] extern const char* const java_type_names[]; - [[gnu::visibility("default")]] extern TypeMapModule map_modules[]; - [[gnu::visibility("default")]] extern const TypeMapJava map_java[]; - [[gnu::visibility("default")]] extern const xamarin::android::hash_t map_java_hashes[]; -#endif - - [[gnu::visibility("default")]] extern CompressedAssemblies compressed_assemblies; - [[gnu::visibility("default")]] extern const ApplicationConfig application_config; - [[gnu::visibility("default")]] extern const char* const app_environment_variables[]; - [[gnu::visibility("default")]] extern const char* const app_system_properties[]; - - [[gnu::visibility("default")]] extern const char* const mono_aot_mode_name; - - [[gnu::visibility("default")]] extern XamarinAndroidBundledAssembly bundled_assemblies[]; - [[gnu::visibility("default")]] extern AssemblyStoreSingleAssemblyRuntimeData assembly_store_bundled_assemblies[]; - [[gnu::visibility("default")]] extern AssemblyStoreRuntimeData assembly_store; - - [[gnu::visibility("default")]] extern DSOCacheEntry dso_cache[]; - [[gnu::visibility("default")]] extern DSOCacheEntry aot_dso_cache[]; - [[gnu::visibility("default")]] extern DSOApkEntry dso_apk_entries[]; -} - -// -// Support for marshal methods -// -#if defined (RELEASE) -struct MarshalMethodsManagedClass -{ - const uint32_t token; - void *klass; -}; - -// Number of assembly name forms for which we generate hashes (essentially file name mutations. For instance -// `HelloWorld.dll`, `HelloWorld`, `en-US/HelloWorld` etc). This is multiplied by the number of assemblies in the apk to -// obtain number of entries in the `assembly_image_cache_hashes` and `assembly_image_cache_indices` entries -constexpr uint32_t number_of_assembly_name_forms_in_image_cache = 3; - -// These 3 arrays constitute the cache used to store pointers to loaded managed assemblies. -// Three arrays are used so that we can have multiple hashes pointing to the same MonoImage*. -// -// This is done by the `assembly_image_cache_hashes` containing hashes for all mutations of some -// assembly's name (e.g. with culture prefix, without extension etc) and position of that hash in -// `assembly_image_cache_hashes` is an index into `assembly_image_cache_indices` which, in turn, -// stores final index into the `assembly_image_cache` array. -// -[[gnu::visibility("default")]] extern void* assembly_image_cache[]; -[[gnu::visibility("default")]] extern const uint32_t assembly_image_cache_indices[]; -[[gnu::visibility("default")]] extern const xamarin::android::hash_t assembly_image_cache_hashes[]; - -// Number of unique classes which contain native callbacks we bind -[[gnu::visibility("default")]] extern uint32_t marshal_methods_number_of_classes; -[[gnu::visibility("default")]] extern MarshalMethodsManagedClass marshal_methods_class_cache[]; - -// -// These tables store names of classes and managed callback methods used in the generated marshal methods -// code. They are used just for error reporting. -// -// Class names are found at the same indexes as their corresponding entries in the `marshal_methods_class_cache` array -// above. Method names are stored as token:name pairs and the array must end with an "invalid" terminator entry (token -// == 0; name == nullptr) -// -struct MarshalMethodName -{ - // combination of assembly index (high 32 bits) and method token (low 32 bits) - const uint64_t id; - const char *name; -}; - -[[gnu::visibility("default")]] extern const char* const mm_class_names[]; -[[gnu::visibility("default")]] extern const MarshalMethodName mm_method_names[]; - -using get_function_pointer_fn = void(*)(uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr); - -[[gnu::visibility("default")]] extern void xamarin_app_init (JNIEnv *env, get_function_pointer_fn fn) noexcept; -#endif // def RELEASE diff --git a/src/native-clr/libnet-android.map.txt b/src/native-clr/libnet-android.map.txt deleted file mode 100644 index 9c8a580bc34..00000000000 --- a/src/native-clr/libnet-android.map.txt +++ /dev/null @@ -1,12 +0,0 @@ -LIBNET_ANDROID { - global: - JNI_OnLoad; - Java_mono_android_Runtime_dumpTimingData; - Java_mono_android_Runtime_initInternal; - Java_mono_android_Runtime_notifyTimeZoneChanged; - Java_mono_android_Runtime_propagateUncaughtException; - Java_mono_android_Runtime_register; - - local: - *; -}; diff --git a/src/native-clr/runtime-base/CMakeLists.txt b/src/native-clr/runtime-base/CMakeLists.txt deleted file mode 100644 index 462a62e36dc..00000000000 --- a/src/native-clr/runtime-base/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -set(LIB_NAME runtime-base) -set(LIB_ALIAS xa::runtime-base-clr) - -set(XA_RUNTIME_BASE_SOURCES - android-system.cc - logger.cc - timing.cc - timing-internal.cc - util.cc -) -add_clang_check_sources("${XA_RUNTIME_BASE_SOURCES}") - -list(APPEND POTENTIAL_LOCAL_COMPILER_ARGS - -ffunction-sections - -fdata-sections -) - -xa_check_c_args(RUNTIME_BASE_CXX_ARGS "${POTENTIAL_LOCAL_COMPILER_ARGS}") - -add_library( - ${LIB_NAME} - STATIC - ${XA_RUNTIME_BASE_SOURCES} -) - -add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) - -set_static_library_suffix(${LIB_NAME}) - -target_compile_options( - ${LIB_NAME} - PRIVATE - ${XA_COMMON_CXX_ARGS} - ${RUNTIME_BASE_CXX_ARGS} -) - -target_include_directories( - ${LIB_NAME} - SYSTEM PRIVATE - ${SYSROOT_CXX_INCLUDE_DIR} -) - -target_link_libraries( - ${LIB_NAME} - PRIVATE - xa::shared-clr - xa::xamarin-app-clr -) - -xa_add_compile_definitions(${LIB_NAME}) -xa_add_include_directories(${LIB_NAME}) diff --git a/src/native-clr/runtime-base/android-system.cc b/src/native-clr/runtime-base/android-system.cc deleted file mode 100644 index 7946cc30580..00000000000 --- a/src/native-clr/runtime-base/android-system.cc +++ /dev/null @@ -1,330 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -using namespace xamarin::android; -using std::operator""sv; - -#if defined(DEBUG) -[[gnu::always_inline]] -void -AndroidSystem::add_system_property (const char *name, const char *value) noexcept -{ - if (name == nullptr || *name == '\0') { - log_warn (LOG_DEFAULT, "Attempt to add a bundled system property without a valid name"); - return; - } - - if (value == nullptr) { - value = ""; - } - - bundled_properties[name] = value; -} - -void -AndroidSystem::setup_environment (const char *name, const char *value) noexcept -{ - if (name == nullptr || *name == '\0') { - return; - } - - const char *v = value; - if (v == nullptr) { - v = ""; - } - - if (isupper (name [0]) || name [0] == '_') { - if (setenv (name, v, 1) < 0) { - log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); - } - return; - } - - add_system_property (name, v); -} - -void -AndroidSystem::setup_environment_from_override_file (dynamic_local_string const& path) noexcept -{ - using read_count_type = size_t; - - struct stat sbuf; - if (::stat (path.get (), &sbuf) < 0) { - log_warn (LOG_DEFAULT, "Failed to stat the environment override file {}: {}", path.get (), strerror (errno)); - return; - } - - int fd = open (path.get (), O_RDONLY); - if (fd < 0) { - log_warn (LOG_DEFAULT, "Failed to open the environment override file {}: {}", path.get (), strerror (errno)); - return; - } - - auto file_size = static_cast(sbuf.st_size); - size_t nread = 0uz; - ssize_t r; - auto buf = std::make_unique (file_size); - - do { - auto read_count = static_cast(file_size - nread); - r = read (fd, buf.get () + nread, read_count); - if (r > 0) { - nread += static_cast(r); - } - } while (r < 0 && errno == EINTR); - - if (nread == 0) { - log_warn (LOG_DEFAULT, "Failed to read the environment override file {}: {}", path.get (), strerror (errno)); - return; - } - - // The file format is as follows (no newlines are used, this is just for illustration - // purposes, comments aren't part of the file either): - // - // # 10 ASCII characters formattted as a C++ hexadecimal number terminated with NUL: name - // # width (including the terminating NUL) - // 0x00000000\0 - // - // # 10 ASCII characters formattted as a C++ hexadecimal number terminated with NUL: value - // # width (including the terminating NUL) - // 0x00000000\0 - // - // # Variable name, terminated with NUL and padded to [name width] with NUL characters - // name\0 - // - // # Variable value, terminated with NUL and padded to [value width] with NUL characters - // value\0 - if (nread < Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) { - log_warn (LOG_DEFAULT, "Invalid format of the environment override file {}: malformatted header", path.get ()); - return; - } - - char *endptr; - unsigned long name_width = strtoul (buf.get (), &endptr, 16); - if ((name_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path.get ()); - return; - } - - unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); - if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path.get ()); - return; - } - - uint64_t data_width = name_width + value_width; - if (data_width > file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path.get ()); - return; - } - - uint64_t data_size = static_cast(file_size); - char *name = buf.get () + Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE; - while (data_size > 0 && data_size >= data_width) { - if (*name == '\0') { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path.get (), name - buf.get ()); - return; - } - - log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path.get (), name, name + name_width); - setup_environment (name, name + name_width); - name += data_width; - data_size -= data_width; - } -} -#endif - -void -AndroidSystem::setup_environment () noexcept -{ - if (application_config.environment_variable_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count); - return; - } - - const char *var_name; - const char *var_value; - for (size_t i = 0uz; i < application_config.environment_variable_count; i += 2) { - var_name = app_environment_variables [i]; - if (var_name == nullptr || *var_name == '\0') { - continue; - } - - var_value = app_environment_variables [i + 1uz]; - if (var_value == nullptr) { - var_value = ""; - } - - if constexpr (Constants::IsDebugBuild) { - log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); - } - - if (setenv (var_name, var_value, 1) < 0) { - log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); - } - } - -#if defined(DEBUG) - log_debug (LOG_DEFAULT, "Loading environment from the override directory."sv); - - dynamic_local_string env_override_file; - Util::path_combine (env_override_file, std::string_view {primary_override_dir}, Constants::OVERRIDE_ENVIRONMENT_FILE_NAME); - log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); - if (Util::file_exists (env_override_file)) { - log_debug (LOG_DEFAULT, "Loading {}"sv, env_override_file.get ()); - setup_environment_from_override_file (env_override_file); - } -#endif // def DEBUG -} - -void -AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept -{ - // appDirs[Constants::APP_DIRS_DATA_DIR_INDEX] points to the native library directory - dynamic_local_string libmonodroid_path; - Util::path_combine (libmonodroid_path, appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_string_view (), "libmonodroid.so"sv); - - log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); - if (!Util::file_exists (libmonodroid_path)) { - log_debug (LOG_ASSEMBLY, "{} 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 {}, assuming application/android:extractNativeLibs == true", appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - set_embedded_dso_mode_enabled (false); - } -} - -auto -AndroidSystem::lookup_system_property (std::string_view const& name, size_t &value_len) noexcept -> const char* -{ - value_len = 0; -#if defined (DEBUG) - if (!bundled_properties.empty ()) { - auto prop_iter = bundled_properties.find (name.data ()); - if (prop_iter != bundled_properties.end ()) { - value_len = prop_iter->second.length (); - return prop_iter->first.c_str (); - } - } -#endif // DEBUG - - if (application_config.system_property_count == 0) { - return nullptr; - } - - if (application_config.system_property_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count); - return nullptr; - } - - const char *prop_name; - const char *prop_value; - for (size_t i = 0uz; i < application_config.system_property_count; i += 2uz) { - prop_name = app_system_properties[i]; - if (prop_name == nullptr || *prop_name == '\0') { - continue; - } - - if (strcmp (prop_name, name.data ()) == 0) { - prop_value = app_system_properties [i + 1uz]; - if (prop_value == nullptr || *prop_value == '\0') { - value_len = 0uz; - return ""; - } - - value_len = strlen (prop_value); - return prop_value; - } - } - - return nullptr; -} - -auto -AndroidSystem::monodroid__system_property_get (std::string_view const& name, char *sp_value, size_t sp_value_len) noexcept -> int -{ - if (name.empty () || sp_value == nullptr) { - return -1; - } - - char *buf = nullptr; - if (sp_value_len < Constants::PROPERTY_VALUE_BUFFER_LEN) { - size_t alloc_size = Helpers::add_with_overflow_check (Constants::PROPERTY_VALUE_BUFFER_LEN, 1uz); - log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); - buf = new char [alloc_size]; - } - - int len = __system_property_get (name.data (), buf ? buf : sp_value); - if (buf != nullptr) { - strncpy (sp_value, buf, sp_value_len); - sp_value [sp_value_len] = '\0'; - delete[] buf; - } - - return len; -} - -auto AndroidSystem::monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int -{ - int len = monodroid__system_property_get (name, value.get (), value.size ()); - if (len > 0) { - // Clumsy, but if we want direct writes to be fast, this is the price we pay - value.set_length_after_direct_write (static_cast(len)); - return len; - } - - size_t plen; - const char *v = lookup_system_property (name, plen); - if (v == nullptr) { - return len; - } - - value.assign (v, plen); - return Helpers::add_with_overflow_check (plen, 0); -} - -auto -AndroidSystem::get_max_gref_count_from_system () noexcept -> long -{ - long max; - - if (running_in_emulator) { - max = 2000; - } else { - max = 51200; - } - - dynamic_local_string override; - if (monodroid_get_system_property (Constants::DEBUG_MONO_MAX_GREFC, override) > 0) { - char *e; - max = strtol (override.get (), &e, 10); - switch (*e) { - case 'k': - e++; - max *= 1000; - break; - case 'm': - e++; - max *= 1000000; - break; - } - - if (max < 0) { - max = std::numeric_limits::max (); - } - - if (*e) { - log_warn (LOG_GC, "Unsupported '{}' value '{}'.", Constants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); - } - - log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); - } - - return max; -} diff --git a/src/native-clr/runtime-base/logger.cc b/src/native-clr/runtime-base/logger.cc deleted file mode 100644 index c0d06769988..00000000000 --- a/src/native-clr/runtime-base/logger.cc +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -using namespace xamarin::android; -using std::operator""sv; - -namespace { - FILE* - open_file (LogCategories category, std::string const& custom_path, std::string_view const& override_dir, std::string_view const& filename) - { - bool ignore_path = false; - if (!custom_path.empty () && access (custom_path.c_str (), W_OK) < 0) { - log_warn (category, - "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", - custom_path, - strerror (errno), - override_dir, - filename - ); - ignore_path = true; - } - - std::string p{}; - if (custom_path.empty () || ignore_path) { - Util::create_public_directory (override_dir); - p.assign (override_dir); - p.append ("/"); - p.append (filename); - } - - std::string const& path = p.empty () ? custom_path : p; - unlink (path.c_str ()); - - FILE *f = Util::monodroid_fopen (path, "a"sv); - - if (f) { - Util::set_world_accessable (path); - } else { - log_warn (category, "Could not open path '{}' for logging: {}", path, strerror (errno)); - } - - return f; - } - - std::string gref_file{}; - std::string lref_file{}; - bool light_gref = false; - bool light_lref = false; -} - -void -Logger::init_reference_logging (std::string_view const& override_dir) noexcept -{ - if ((log_categories & LOG_GREF) != 0 && !light_gref) { - _gref_log = open_file (LOG_GREF, gref_file, override_dir, "grefs.txt"sv); - } - - if ((log_categories & LOG_LREF) != 0 && !light_lref) { - // if both lref & gref have files specified, and they're the same path, reuse the FILE*. - if (!lref_file.empty () && strcmp (lref_file.c_str (), !gref_file.empty () ? gref_file.c_str () : "") == 0) { - _lref_log = _gref_log; - } else { - _lref_log = open_file (LOG_LREF, lref_file, override_dir, "lrefs.txt"sv); - } - } -} - -[[gnu::always_inline]] bool -Logger::set_category (std::string_view const& name, string_segment& arg, unsigned int entry, bool arg_starts_with_name) noexcept -{ - if ((log_categories & entry) == entry) { - return false; - } - - if (arg_starts_with_name ? arg.starts_with (name) : arg.equal (name)) { - log_categories |= entry; - return true; - } - - return false; -} - -void -Logger::init_logging_categories () noexcept -{ - _log_timing_categories = LogTimingCategories::Default; - - dynamic_local_string value; - if (AndroidSystem::monodroid_get_system_property (Constants::DEBUG_MONO_LOG_PROPERTY, value) == 0) { - return; - } - - string_segment param; - while (value.next_token (',', param)) { - constexpr std::string_view CAT_ALL { "all" }; - - if (param.equal (CAT_ALL)) { - log_categories = 0xFFFFFFFF; - break; - } - - if (set_category ("assembly", param, LOG_ASSEMBLY)) { - continue; - } - - if (set_category ("default", param, LOG_DEFAULT)) { - continue; - } - - if (set_category ("debugger", param, LOG_DEBUGGER)) { - continue; - } - - if (set_category ("gc", param, LOG_GC)) { - continue; - } - - if (set_category ("gref", param, LOG_GREF)) { - continue; - } - - if (set_category ("lref", param, LOG_LREF)) { - continue; - } - - if (set_category ("timing", param, LOG_TIMING)) { - continue; - } - - if (set_category ("network", param, LOG_NET)) { - continue; - } - - if (set_category ("netlink", param, LOG_NETLINK)) { - continue; - } - - auto get_log_file_name = [](std::string_view const& file_kind, string_segment const& segment, size_t offset) -> const char* { - auto file_name = segment.at (offset); - - if (!file_name.has_value ()) { - log_warn (LOG_DEFAULT, "Unable to set path to {} log file: {}", file_kind, to_string (file_name.error ())); - return nullptr; - } - - return file_name.value (); - }; - - constexpr std::string_view CAT_GREF_EQUALS { "gref=" }; - if (set_category (CAT_GREF_EQUALS, param, LOG_GREF, true /* arg_starts_with_name */)) { - gref_file = get_log_file_name ("gref"sv, param, CAT_GREF_EQUALS.length ()); - continue; - } - - if (set_category ("gref-", param, LOG_GREF)) { - light_gref = true; - continue; - } - - if (set_category ("gref+", param, LOG_GREF)) { - _gref_to_logcat = true; - continue; - } - - constexpr std::string_view CAT_LREF_EQUALS { "lref=" }; - if (set_category (CAT_LREF_EQUALS, param, LOG_LREF, true /* arg_starts_with_name */)) { - lref_file = get_log_file_name ("lref"sv, param, CAT_LREF_EQUALS.length ()); - continue; - } - - if (set_category ("lref-", param, LOG_LREF)) { - light_lref = true; - continue; - } - - if (set_category ("lref+", param, LOG_LREF)) { - _lref_to_logcat = true; - continue; - } - - if (param.starts_with ("timing=fast-bare")) { - log_categories |= LOG_TIMING; - _log_timing_categories |= LogTimingCategories::FastBare; - continue; - } - - if (param.starts_with ("timing=bare")) { - log_categories |= LOG_TIMING; - _log_timing_categories |= LogTimingCategories::Bare; - continue; - } - } - - if ((log_categories & LOG_GC) != 0) { - _gc_spew_enabled = true; - } -} diff --git a/src/native-clr/runtime-base/timing-internal.cc b/src/native-clr/runtime-base/timing-internal.cc deleted file mode 100644 index fab5e4ed160..00000000000 --- a/src/native-clr/runtime-base/timing-internal.cc +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include - -using namespace xamarin::android; - -namespace xamarin::android { - FastTiming *internal_timing = nullptr; -} - -void -FastTiming::really_initialize (bool log_immediately) noexcept -{ - internal_timing = new FastTiming (); - is_enabled = true; - immediate_logging = log_immediately; - - if (immediate_logging) { - return; - } - - log_write (LOG_TIMING, LogLevel::Info, "[2/1] To get timing results, send the mono.android.app.DUMP_TIMING_DATA intent to the application"); -} - -void -FastTiming::dump () noexcept -{ - if (immediate_logging) { - return; - } - - StartupAwareLock lock { event_vector_realloc_mutex }; - size_t entries = next_event_index.load (); - - log_write (LOG_TIMING, LogLevel::Info, "[2/2] Performance measurement results"); - if (entries == 0) { - log_write (LOG_TIMING, LogLevel::Info, "[2/3] No events logged"); - return; - } - - dynamic_local_string message; - - // Values are in nanoseconds - uint64_t total_assembly_load_time = 0u; - uint64_t total_java_to_managed_time = 0u; - uint64_t total_managed_to_java_time = 0u; - uint64_t total_ns; - - format_and_log (init_time, message, total_ns, true /* indent */); - for (size_t i = 0uz; i < entries; i++) { - TimingEvent const& event = events[i]; - format_and_log (event, message, total_ns, true /* indent */); - - switch (event.kind) { - case TimingEventKind::AssemblyLoad: - total_assembly_load_time += total_ns; - break; - - case TimingEventKind::JavaToManaged: - total_java_to_managed_time += total_ns; - break; - - case TimingEventKind::ManagedToJava: - total_managed_to_java_time += total_ns; - break; - - default: - // Ignore other kinds - break; - } - } - - uint32_t sec, ms, ns; - log_write (LOG_TIMING, LogLevel::Info, "[2/4] Accumulated performance results"); - - ns_to_time (total_assembly_load_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/5] Assembly load: {}:{}::{}", sec, ms, ns); - - ns_to_time (total_java_to_managed_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/6] Java to Managed lookup: {}:{}::{}", sec, ms, ns); - - ns_to_time (total_managed_to_java_time, sec, ms, ns); - log_info_nocheck (LOG_TIMING, " [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns); -} diff --git a/src/native-clr/runtime-base/timing.cc b/src/native-clr/runtime-base/timing.cc deleted file mode 100644 index 930139e06e4..00000000000 --- a/src/native-clr/runtime-base/timing.cc +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -using namespace xamarin::android; - -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-clr/runtime-base/util.cc b/src/native-clr/runtime-base/util.cc deleted file mode 100644 index 6cce7591a6a..00000000000 --- a/src/native-clr/runtime-base/util.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include - -#include - -#include -#include - -using namespace xamarin::android; - -int -Util::create_directory (const char *pathname, mode_t mode) -{ - // if (mode <= 0) - // mode = DEFAULT_DIRECTORY_MODE; - - // if (!pathname || *pathname == '\0') { - // errno = EINVAL; - // return -1; - // } - // mode_t oldumask = umask (022); - // std::unique_ptr path {strdup_new (pathname)}; - // int rv, ret = 0; - // for (char *d = path.get (); d != nullptr && *d; ++d) { - // if (*d != '/') - // continue; - // *d = 0; - // if (*path) { - // rv = make_directory (path.get (), mode); - // if (rv == -1 && errno != EEXIST) { - // ret = -1; - // break; - // } - // } - // *d = '/'; - // } - - // if (ret == 0) - // ret = make_directory (pathname, mode); - // umask (oldumask); - - // return ret; - return -1; -} - -void -Util::create_public_directory (std::string_view const& dir) -{ - mode_t m = umask (0); - int ret = mkdir (dir.data (), 0777); - if (ret < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); - } - umask (m); -} - -auto -Util::monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE* -{ - /* On Unix, both path and system calls are all assumed - * to be UTF-8 compliant. - */ - FILE *ret = fopen (filename.data (), mode.data ()); - if (ret == nullptr) { - log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); - return nullptr; - } - - return ret; -} - -void Util::set_world_accessable (std::string_view const& path) -{ - int r; - do { - r = chmod (path.data (), 0664); - } while (r == -1 && errno == EINTR); - - if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); - } -} diff --git a/src/native-clr/shared/CMakeLists.txt b/src/native-clr/shared/CMakeLists.txt deleted file mode 100644 index c1a85951663..00000000000 --- a/src/native-clr/shared/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -set(LIB_NAME xa-shared-bits) -set(LIB_ALIAS xa::shared-clr) - -set(XA_SHARED_SOURCES - helpers.cc - log_functions.cc -) -add_clang_check_sources("${XA_SHARED_SOURCES};") - -add_library( - ${LIB_NAME} - STATIC - ${XA_SHARED_SOURCES} -) -add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) - -set_static_library_suffix(${LIB_NAME}) - -macro(lib_target_options TARGET_NAME) - target_include_directories( - ${TARGET_NAME} - PUBLIC - "$" - "$" - ) - - target_link_libraries( - ${TARGET_NAME} - PUBLIC - xa::java-interop-clr - -llog - ) - - target_include_directories( - ${TARGET_NAME} - SYSTEM PRIVATE - ${SYSROOT_CXX_INCLUDE_DIR} - ) - - target_compile_options( - ${TARGET_NAME} - PRIVATE - ${XA_COMMON_CXX_ARGS} - ) - - xa_add_compile_definitions(${TARGET_NAME}) - xa_add_include_directories(${TARGET_NAME}) -endmacro() - -lib_target_options(${LIB_NAME}) diff --git a/src/native-clr/shared/helpers.cc b/src/native-clr/shared/helpers.cc deleted file mode 100644 index 59697e7d257..00000000000 --- a/src/native-clr/shared/helpers.cc +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include - -#include -#include - -using namespace xamarin::android; - -[[noreturn]] void -Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept -{ - // Log it, but also... - log_fatal (category, "{}", message); - - // ...let android include it in the tombstone, debuggerd output, stack trace etc - android_set_abort_message (message); - - if (log_location) { - // We don't want to log the full path, just the file name. libc++ uses full file path here. - const char *file_name = sloc.file_name (); - const char *last_path_sep = strrchr (file_name, '/'); - - if (last_path_sep == nullptr) [[unlikely]] { - // In case we were built on Windows - last_path_sep = strrchr (file_name, '\\'); - } - - if (last_path_sep != nullptr) [[likely]] { - last_path_sep++; - if (*last_path_sep != '\0') [[unlikely]] { - file_name = last_path_sep; - } - } - - log_fatal ( - category, - "Abort at {}:{}:{} ('%s')", - file_name, - sloc.line (), - sloc.column (), - sloc.function_name () - ); - } - std::abort (); -} diff --git a/src/native-clr/shared/log_functions.cc b/src/native-clr/shared/log_functions.cc deleted file mode 100644 index acd5e705c06..00000000000 --- a/src/native-clr/shared/log_functions.cc +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "java-interop-logger.h" -#include -#include - -using namespace xamarin::android; - -namespace { - // Must match the same ordering as LogCategories - constexpr std::array log_names = { - Constants::LOG_CATEGORY_NAME_NONE, - Constants::LOG_CATEGORY_NAME_MONODROID, - Constants::LOG_CATEGORY_NAME_MONODROID_ASSEMBLY, - Constants::LOG_CATEGORY_NAME_MONODROID_DEBUG, - Constants::LOG_CATEGORY_NAME_MONODROID_GC, - Constants::LOG_CATEGORY_NAME_MONODROID_GREF, - Constants::LOG_CATEGORY_NAME_MONODROID_LREF, - Constants::LOG_CATEGORY_NAME_MONODROID_TIMING, - Constants::LOG_CATEGORY_NAME_MONODROID_BUNDLE, - Constants::LOG_CATEGORY_NAME_MONODROID_NETWORK, - Constants::LOG_CATEGORY_NAME_MONODROID_NETLINK, - Constants::LOG_CATEGORY_NAME_ERROR, - }; - - [[gnu::always_inline]] - constexpr auto category_name (int value) noexcept -> const char* - { - if (value == 0) { - return log_names[0].data (); - } - - // ffs(value) returns index of lowest bit set in `value` - return log_names [static_cast(ffs (value))].data (); - } - - constexpr android_LogPriority DEFAULT_PRIORITY = ANDROID_LOG_INFO; - - // relies on the fact that the LogLevel enum has sequential values - 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 - }; - - constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1; -} - -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) != category) { - 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) != category) { - return; - } - - DO_LOG (ANDROID_LOG_DEBUG, category, format, args); -} - -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-clr/startup/CMakeLists.txt b/src/native-clr/startup/CMakeLists.txt deleted file mode 100644 index 2f6951c6275..00000000000 --- a/src/native-clr/startup/CMakeLists.txt +++ /dev/null @@ -1,53 +0,0 @@ -set(LIB_NAME xamarin-startup) -set(LIB_ALIAS xa::xamarin-startup-clr) - -set(XAMARIN_STARTUP_SOURCES - zip.cc -) -add_clang_check_sources("${XAMARIN_STARTUP_SOURCES}") - -add_library( - ${LIB_NAME} - STATIC - ${XAMARIN_STARTUP_SOURCES} -) - -add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) -set_static_library_suffix(${LIB_NAME}) - -target_include_directories( - ${LIB_NAME} - SYSTEM PRIVATE - ${SYSROOT_CXX_INCLUDE_DIR} -) - -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 -) - -target_link_directories( - ${LIB_NAME} - PRIVATE - ${NET_RUNTIME_DIR}/native-clr -) - -target_link_options( - ${LIB_NAME} - PRIVATE - ${XA_COMMON_CXX_LINKER_ARGS} - ${XA_CXX_DSO_LINKER_ARGS} -) - -target_link_libraries( - ${LIB_NAME} - PRIVATE - xa::shared-clr - -llog -) - -xa_add_compile_definitions(${LIB_NAME}) -xa_add_include_directories(${LIB_NAME}) diff --git a/src/native-clr/startup/zip.cc b/src/native-clr/startup/zip.cc deleted file mode 100644 index cef57b26618..00000000000 --- a/src/native-clr/startup/zip.cc +++ /dev/null @@ -1,3 +0,0 @@ -#include - -using namespace xamarin::android; diff --git a/src/native-clr/xamarin-app-stub/CMakeLists.txt b/src/native-clr/xamarin-app-stub/CMakeLists.txt deleted file mode 100644 index d23328f9ce7..00000000000 --- a/src/native-clr/xamarin-app-stub/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -set(LIB_NAME xamarin-app-clr) -set(LIB_ALIAS xa::xamarin-app-clr) - -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} - SYSTEM PRIVATE - ${SYSROOT_CXX_INCLUDE_DIR} -) - -target_compile_options( - ${LIB_NAME} - PRIVATE - ${XA_COMMON_CXX_ARGS} -) - -target_link_options( - ${LIB_NAME} - PRIVATE - ${XA_COMMON_CXX_LINKER_ARGS} - ${XA_CXX_DSO_LINKER_ARGS} -) - -target_link_libraries( - ${LIB_NAME} - PRIVATE - ${SHARED_LIB_NAME} -) - -if(DEBUG_BUILD) - set(LIB_SUBDIR "Debug") -else() - set(LIB_SUBDIR "Release") -endif() - -set_target_properties( - ${LIB_NAME} - PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIB_SUBDIR}" -) - -xa_add_compile_definitions(${LIB_NAME}) -xa_add_include_directories(${LIB_NAME}) diff --git a/src/native-clr/xamarin-app-stub/application_dso_stub.cc b/src/native-clr/xamarin-app-stub/application_dso_stub.cc deleted file mode 100644 index 2a34ff4c13d..00000000000 --- a/src/native-clr/xamarin-app-stub/application_dso_stub.cc +++ /dev/null @@ -1,298 +0,0 @@ -#include -#include - -#include -#include - -// This file MUST have "valid" values everywhere - the DSO it is compiled into is loaded by the -// designer on desktop. -const uint64_t format_tag = FORMAT_TAG; - -#if defined (DEBUG) -static TypeMapEntry java_to_managed[] = {}; - -static TypeMapEntry managed_to_java[] = {}; - -// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs -const TypeMap type_map = { - 0, - nullptr, - nullptr, - java_to_managed, - managed_to_java -}; -#else -const uint32_t map_module_count = 0; -const uint32_t java_type_count = 0; -const char* const java_type_names[] = {}; - -TypeMapModule map_modules[] = {}; -const TypeMapJava map_java[] = {}; -const xamarin::android::hash_t map_java_hashes[] = {}; -#endif - -CompressedAssemblies compressed_assemblies = { - .count = 0, - .descriptors = nullptr, -}; - -// -// Config settings below **must** be valid for Desktop builds as the default `libxamarin-app.{dll,dylib,so}` is used by -// the Designer -// -constexpr char android_package_name[] = "com.xamarin.test"; -const ApplicationConfig application_config = { - .uses_assembly_preload = false, - .jni_add_native_method_registration_attribute_present = false, - .have_runtime_config_blob = false, - .marshal_methods_enabled = false, - .ignore_split_configs = false, - .package_naming_policy = 0, - .environment_variable_count = 0, - .system_property_count = 0, - .number_of_assemblies_in_apk = 2, - .bundled_assembly_name_width = 0, - .number_of_dso_cache_entries = 2, - .number_of_shared_libraries = 2, - .android_runtime_jnienv_class_token = 1, - .jnienv_initialize_method_token = 2, - .jnienv_registerjninatives_method_token = 3, - .jni_remapping_replacement_type_count = 2, - .jni_remapping_replacement_method_index_entry_count = 2, - .android_package_name = android_package_name, -}; - -// TODO: migrate to std::string_view for these two -const char* const app_environment_variables[] = {}; -const char* const app_system_properties[] = {}; - -static constexpr size_t AssemblyNameWidth = 128uz; - -static char first_assembly_name[AssemblyNameWidth]; -static char second_assembly_name[AssemblyNameWidth]; - -XamarinAndroidBundledAssembly bundled_assemblies[] = { - { - .file_fd = -1, - .file_name = nullptr, - .data_offset = 0, - .data_size = 0, - .data = nullptr, - .name_length = 0, - .name = first_assembly_name, - }, - - { - .file_fd = -1, - .file_name = nullptr, - .data_offset = 0, - .data_size = 0, - .data = nullptr, - .name_length = 0, - .name = second_assembly_name, - }, -}; - -AssemblyStoreSingleAssemblyRuntimeData assembly_store_bundled_assemblies[] = { - { - .image_data = nullptr, - .debug_info_data = nullptr, - .config_data = nullptr, - .descriptor = nullptr, - }, - - { - .image_data = nullptr, - .debug_info_data = nullptr, - .config_data = nullptr, - .descriptor = nullptr, - }, -}; - -AssemblyStoreRuntimeData assembly_store = { - .data_start = nullptr, - .assembly_count = 0, - .index_entry_count = 0, - .assemblies = nullptr, -}; - -constexpr char fake_dso_name[] = "libaot-Some.Assembly.dll.so"; -constexpr char fake_dso_name2[] = "libaot-Another.Assembly.dll.so"; - -DSOCacheEntry dso_cache[] = { - { - .hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), - .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), - .ignore = true, - .name = fake_dso_name, - .handle = nullptr, - }, - - { - .hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), - .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), - .ignore = true, - .name = fake_dso_name2, - .handle = nullptr, - }, -}; - -DSOCacheEntry aot_dso_cache[] = { - { - .hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), - .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name, sizeof(fake_dso_name) - 1), - .ignore = true, - .name = fake_dso_name, - .handle = nullptr, - }, - - { - .hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), - .real_name_hash = xamarin::android::xxhash::hash (fake_dso_name2, sizeof(fake_dso_name2) - 1), - .ignore = true, - .name = fake_dso_name2, - .handle = nullptr, - }, -}; - -DSOApkEntry dso_apk_entries[2] {}; - -// -// Support for marshal methods -// -#if defined (RELEASE) -void* assembly_image_cache[] = { - nullptr, - nullptr, - -}; - -// Each element contains an index into `assembly_image_cache` -const uint32_t assembly_image_cache_indices[] = { - 0, - 1, - 1, - 1, -}; - -// hashes point to indices in `assembly_image_cache_indices` -const xamarin::android::hash_t assembly_image_cache_hashes[] = { - 0, - 1, - 2, - 3, -}; - -uint32_t marshal_methods_number_of_classes = 2; -MarshalMethodsManagedClass marshal_methods_class_cache[] = { - { - .token = 0, - .klass = nullptr, - }, - - { - .token = 0, - .klass = nullptr, - }, -}; - -const char* const mm_class_names[2] = { - "one", - "two", -}; - -const MarshalMethodName mm_method_names[] = { - { - .id = 1, - .name = "one", - }, - - { - .id = 2, - .name = "two", - }, -}; - -void xamarin_app_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] get_function_pointer_fn fn) noexcept -{ - // Dummy -} -#endif // def RELEASE - -static const JniRemappingIndexMethodEntry some_java_type_one_methods[] = { - { - .name = { - .length = 15, - .str = "old_method_name", - }, - - .signature = { - .length = 0, - .str = nullptr, - }, - - .replacement = { - .target_type = "some/java/target_type_one", - .target_name = "new_method_name", - .is_static = false, - } - }, -}; - -static const JniRemappingIndexMethodEntry some_java_type_two_methods[] = { - { - .name = { - .length = 15, - .str = "old_method_name", - }, - - .signature = { - .length = 28, - .str = "(IILandroid/content/Intent;)", - }, - - .replacement = { - .target_type = "some/java/target_type_two", - .target_name = "new_method_name", - .is_static = true, - } - }, -}; - -const JniRemappingIndexTypeEntry jni_remapping_method_replacement_index[] = { - { - .name = { - .length = 18, - .str = "some/java/type_one", - }, - .method_count = 1, - .methods = some_java_type_one_methods, - }, - - { - .name = { - .length = 18, - .str = "some/java/type_two", - }, - .method_count = 1, - .methods = some_java_type_two_methods, - }, -}; - -const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[] = { - { - .name = { - .length = 14, - .str = "some/java/type", - }, - .replacement = "another/java/type", - }, - - { - .name = { - .length = 20, - .str = "some/other/java/type", - }, - .replacement = "another/replacement/java/type", - }, -}; diff --git a/src/native/.gitignore b/src/native/.gitignore deleted file mode 100644 index 06af5ee0acd..00000000000 --- a/src/native/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -CMakeUserPresets.json -CMakePresets.json -static-analysis.*.txt diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index a1cee1367a6..ddd4d72a19c 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -46,7 +46,7 @@ include("${CMAKE_ANDROID_NDK}/build/cmake/abis.cmake") include("${CMAKE_SOURCE_DIR}/cmake/ArchiveDSOStub.cmake") string(TOLOWER "${RUNTIME_FLAVOR}" RUNTIME_FLAVOR_LOWER) -if (RUNTIME_FLAVOR_LOWER STREQUAL monovm) +if (RUNTIME_FLAVOR_LOWER STREQUAL mono) set(IS_MONO_RUNTIME True) set(IS_CLR_RUNTIME False) set(SOURCES_PREFIX "mono") @@ -576,25 +576,25 @@ else() add_subdirectory(${SOURCES_PREFIX}/xamarin-app-stub) if (IS_MONO_RUNTIME) - add_subdirectory(mono/tracing) - add_subdirectory(mono/pinvoke-override) + add_subdirectory(mono/tracing) + add_subdirectory(mono/pinvoke-override) - if(DEBUG_BUILD) + if(DEBUG_BUILD) add_subdirectory(mono/xamarin-debug-app-helper) - endif() + endif() - add_subdirectory(mono/monodroid) + add_subdirectory(mono/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 - ) + 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 + ) endif() if (IS_CLR_RUNTIME) - add_subdirectory(clr/host) - add_subdirectory(clr/startup) + add_subdirectory(clr/host) + add_subdirectory(clr/startup) endif() endif() diff --git a/src/native/CMakePresets.json.in b/src/native/CMakePresets.json.in index 5544b1252b0..33c910f6845 100644 --- a/src/native/CMakePresets.json.in +++ b/src/native/CMakePresets.json.in @@ -21,6 +21,7 @@ "ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES": "ON", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", "CMAKE_MAKE_PROGRAM": "@NinjaPath@", + "OUTPUT_PATH": "@OutputPath@", "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", "XA_BUILD_CONFIGURATION": "@XA_BUILD_CONFIGURATION@" } diff --git a/src/native-clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt similarity index 100% rename from src/native-clr/host/CMakeLists.txt rename to src/native/clr/host/CMakeLists.txt diff --git a/src/native-clr/host/host-jni.cc b/src/native/clr/host/host-jni.cc similarity index 100% rename from src/native-clr/host/host-jni.cc rename to src/native/clr/host/host-jni.cc diff --git a/src/native-clr/host/host.cc b/src/native/clr/host/host.cc similarity index 100% rename from src/native-clr/host/host.cc rename to src/native/clr/host/host.cc diff --git a/src/native/clr/include/constants.hh b/src/native/clr/include/constants.hh index 5cb344e3cf4..f024da0a6eb 100644 --- a/src/native/clr/include/constants.hh +++ b/src/native/clr/include/constants.hh @@ -5,7 +5,7 @@ #include -#include +#include "shared/cpp-util.hh" namespace xamarin::android { class Constants @@ -17,18 +17,12 @@ namespace xamarin::android { #endif public: -#if INTPTR_MAX == INT64_MAX - static inline constexpr bool is_64_bit_target = true; -#else - static inline constexpr bool is_64_bit_target = false; -#endif - #if defined(RELEASE) - static constexpr bool is_release_build = true; - static constexpr bool is_debug_build = false; + static constexpr bool IsReleaseBuild = true; + static constexpr bool IsDebugBuild = false; #else - static constexpr bool is_release_build = false; - static constexpr bool is_debug_build = true; + static constexpr bool IsReleaseBuild = false; + static constexpr bool IsDebugBuild = true; #endif static constexpr std::string_view MANGLED_ASSEMBLY_NAME_EXT { ".so" }; @@ -91,10 +85,7 @@ namespace xamarin::android { static constexpr std::string_view split_config_prefix { "/split_config." }; static constexpr std::string_view split_config_extension { ".apk" }; - private: static constexpr size_t split_config_abi_apk_name_size = calc_size (split_config_prefix, android_abi, split_config_extension); - - public: static constexpr auto split_config_abi_apk_name = concat_string_views (split_config_prefix, android_abi, split_config_extension); // @@ -124,20 +115,5 @@ namespace xamarin::android { static constexpr std::string_view OVERRIDE_ENVIRONMENT_FILE_NAME { "environment" }; static constexpr uint32_t OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE = 22; #endif - - static constexpr std::string_view MONO_ANDROID_ASSEMBLY_NAME { "Mono.Android" }; - static constexpr std::string_view ANDROID_RUNTIME_NS_NAME { "Android.Runtime" }; - static constexpr std::string_view JNIENVINIT_CLASS_NAME { "JNIEnvInit" }; - static constexpr std::string_view JNIENV_CLASS_NAME { "JNIEnv" }; - - private: - static constexpr size_t JNIENVINIT_FULL_TYPE_NAME_SIZE = calc_size (ANDROID_RUNTIME_NS_NAME, "."sv, JNIENVINIT_CLASS_NAME); - static constexpr auto JNIENVINIT_FULL_TYPE_NAME_ARRAY = concat_string_views (ANDROID_RUNTIME_NS_NAME, "."sv, JNIENVINIT_CLASS_NAME); - - public: - static constexpr std::string_view JNIENVINIT_FULL_TYPE_NAME { JNIENVINIT_FULL_TYPE_NAME_ARRAY.data () }; - - static constexpr std::string_view ANDROID_ENVIRONMENT_CLASS_NAME { "AndroidEnvironment" }; - static constexpr std::string_view ANDROID_RUNTIME_INTERNAL_CLASS_NAME { "AndroidRuntimeInternal" }; }; } diff --git a/src/native-clr/include/host/host-jni.hh b/src/native/clr/include/host/host-jni.hh similarity index 100% rename from src/native-clr/include/host/host-jni.hh rename to src/native/clr/include/host/host-jni.hh diff --git a/src/native-clr/include/host/host.hh b/src/native/clr/include/host/host.hh similarity index 100% rename from src/native-clr/include/host/host.hh rename to src/native/clr/include/host/host.hh diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index 24324da2353..cf21b566dca 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -1,16 +1,13 @@ #pragma once -#include -#include #include #include #include #include "../constants.hh" #include "../shared/log_types.hh" -#include "../runtime-base/cpu-arch.hh" -#include -#include +#include "jni-wrappers.hh" +#include "strings.hh" #include "util.hh" struct BundledProperty; @@ -18,33 +15,7 @@ struct BundledProperty; namespace xamarin::android { class AndroidSystem { - // 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; - - // TODO: override dirs not implemented - inline static std::array override_dirs{}; - - static constexpr std::array android_abi_names { - std::string_view { "unknown" }, // CPU_KIND_UNKNOWN - std::string_view { "armeabi-v7a" }, // CPU_KIND_ARM - std::string_view { "arm64-v8a" }, // CPU_KIND_ARM64 - std::string_view { "mips" }, // CPU_KIND_MIPS - std::string_view { "x86" }, // CPU_KIND_X86 - std::string_view { "x86_64" }, // CPU_KIND_X86_64 - std::string_view { "riscv" }, // CPU_KIND_RISCV - }; - public: - static auto get_gref_gc_threshold () noexcept -> long - { - if (max_gref_count == std::numeric_limits::max ()) { - return max_gref_count; - } - return static_cast ((max_gref_count * 90LL) / 100LL); - } - static auto get_max_gref_count () noexcept -> long { return max_gref_count; @@ -72,7 +43,7 @@ namespace xamarin::android { static void create_update_dir (std::string const& override_dir) noexcept { - if constexpr (Constants::is_release_build) { + if constexpr (Constants::IsReleaseBuild) { /* * Don't create .__override__ on Release builds, because Google requires * that pre-loaded apps not create world-writable directories. @@ -90,30 +61,14 @@ namespace xamarin::android { log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); } - static auto is_embedded_dso_mode_enabled () noexcept -> bool - { - return embedded_dso_mode_enabled; - } - static auto monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int; static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; static void setup_environment () noexcept; - static void setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) noexcept; - static auto load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check) noexcept -> void*; - static auto load_dso_from_any_directories (const char *name, unsigned int dl_flags) noexcept -> void*; private: - static auto get_full_dso_path (std::string const& base_dir, const char *dso_path, dynamic_local_string& path) noexcept -> bool; - - template // TODO: replace with a concept - static auto load_dso_from_specified_dirs (TContainer directories, const char *dso_name, unsigned int dl_flags) noexcept -> void*; - static auto load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags) noexcept -> void*; - static auto load_dso_from_override_dirs (const char *name, unsigned int dl_flags) noexcept -> void*; static auto lookup_system_property (std::string_view const &name, size_t &value_len) noexcept -> const char*; static auto monodroid__system_property_get (std::string_view const&, char *sp_value, size_t sp_value_len) noexcept -> int; static auto get_max_gref_count_from_system () noexcept -> long; - static void add_apk_libdir (std::string_view const& apk, size_t &index, std::string_view const& abi) noexcept; - static void setup_apk_directories (unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks, bool have_split_apks) noexcept; #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; diff --git a/src/native-clr/include/runtime-base/jni-wrappers.hh b/src/native/clr/include/runtime-base/jni-wrappers.hh similarity index 100% rename from src/native-clr/include/runtime-base/jni-wrappers.hh rename to src/native/clr/include/runtime-base/jni-wrappers.hh diff --git a/src/native/clr/include/runtime-base/logger.hh b/src/native/clr/include/runtime-base/logger.hh index f9285456bc6..45c9e2449bd 100644 --- a/src/native/clr/include/runtime-base/logger.hh +++ b/src/native/clr/include/runtime-base/logger.hh @@ -5,7 +5,7 @@ #include #include -#include +#include "strings.hh" namespace xamarin::android { class Logger diff --git a/src/native-clr/include/runtime-base/strings.hh b/src/native/clr/include/runtime-base/strings.hh similarity index 100% rename from src/native-clr/include/runtime-base/strings.hh rename to src/native/clr/include/runtime-base/strings.hh diff --git a/src/native/clr/include/runtime-base/timing-internal.hh b/src/native/clr/include/runtime-base/timing-internal.hh index 6897c34df1d..d9c29ca53a9 100644 --- a/src/native/clr/include/runtime-base/timing-internal.hh +++ b/src/native/clr/include/runtime-base/timing-internal.hh @@ -10,7 +10,7 @@ #include #include #include "startup-aware-lock.hh" -#include +#include "strings.hh" #include "util.hh" #include "../constants.hh" #include "monodroid-state.hh" diff --git a/src/native/clr/include/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 78100e05a71..555b81e8db2 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -1,21 +1,16 @@ #pragma once -#include -#include -#include -#include - -#include #include #include #include +#include + #include "../constants.hh" -#include -#include "archive-dso-stub-config.hh" -#include +#include "../shared/helpers.hh" +#include "jni-wrappers.hh" #include "logger.hh" -#include +#include "strings.hh" namespace xamarin::android { namespace detail { @@ -31,12 +26,6 @@ namespace xamarin::android { std::derived_from, dynamic_local_storage> || std::derived_from, static_local_storage>; }; - - struct mmap_info - { - void *area; - size_t size; - }; } class Util @@ -84,8 +73,8 @@ namespace xamarin::android { { if (createDirectory) { int rv = create_directory (value.get_cstr (), mode); - if (rv < 0 && errno != EEXIST) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}' for environment variable '{}'. {}", value.get_string_view (), name, strerror (errno)); + if (rv < 0 && errno != EEXIST) { + log_warn (LOG_DEFAULT, "Failed to create directory '{}' for environment variable '{}'. {}", value.get_string_view (), name, strerror (errno)); } } set_environment_variable (name, value); @@ -96,95 +85,6 @@ namespace xamarin::android { set_environment_variable_for_directory (name, value, true, Constants::DEFAULT_DIRECTORY_MODE); } - static int monodroid_getpagesize () noexcept - { - return page_size; - } - - static detail::mmap_info mmap_file (int fd, uint32_t offset, size_t size, std::string_view const& filename) noexcept - { - detail::mmap_info file_info; - detail::mmap_info mmap_info; - - size_t pageSize = static_cast(Util::monodroid_getpagesize ()); - size_t offsetFromPage = offset % pageSize; - size_t offsetPage = offset - offsetFromPage; - size_t offsetSize = size + offsetFromPage; - - mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); - - if (mmap_info.area == MAP_FAILED) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Could not mmap APK fd {}: {}; File={}", - fd, - strerror (errno), - filename - ) - ); - } - - mmap_info.size = offsetSize; - file_info.area = pointer_add (mmap_info.area, offsetFromPage); - file_info.size = size; - - log_info ( - LOG_ASSEMBLY, - " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", - mmap_info.area, - pointer_add (mmap_info.area, mmap_info.size), - mmap_info.size, - file_info.area, - pointer_add (file_info.area, file_info.size), - file_info.size, - fd, - filename - ); - - return file_info; - } - - [[gnu::always_inline]] - static std::tuple get_wrapper_dso_payload_pointer_and_size (detail::mmap_info const& map_info, std::string_view const& file_name) noexcept - { - using Elf_Header = std::conditional_t; - using Elf_SHeader = std::conditional_t; - - const void* const mapped_elf = map_info.area; - auto elf_bytes = static_cast(mapped_elf); - auto elf_header = reinterpret_cast(mapped_elf); - - if constexpr (Constants::is_debug_build) { - // In debug mode we might be dealing with plain data, without DSO wrapper - if (elf_header->e_ident[EI_MAG0] != ELFMAG0 || - elf_header->e_ident[EI_MAG1] != ELFMAG1 || - elf_header->e_ident[EI_MAG2] != ELFMAG2 || - elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", file_name); - // Not an ELF image, just return what we mmapped before - return { map_info.area, map_info.size }; - } - } - - auto section_header = reinterpret_cast(elf_bytes + elf_header->e_shoff); - Elf_SHeader const& payload_hdr = section_header[ArchiveDSOStubConfig::PayloadSectionIndex]; - - return { - const_cast(reinterpret_cast (elf_bytes + ArchiveDSOStubConfig::PayloadSectionOffset)), - payload_hdr.sh_size - }; - } - - static auto is_path_rooted (const char *path) noexcept -> bool - { - if (path == nullptr) { - return false; - } - - return path [0] == '/'; - } - private: // TODO: needs some work to accept mixed params of different accepted types template TBuffer, detail::PathComponentString ...TPart> @@ -219,8 +119,5 @@ namespace xamarin::android { { path_combine_common (buf, std::forward(parts)...); } - - private: - static inline int page_size = getpagesize (); }; } diff --git a/src/native-clr/include/shared/cpp-util.hh b/src/native/clr/include/shared/cpp-util.hh similarity index 100% rename from src/native-clr/include/shared/cpp-util.hh rename to src/native/clr/include/shared/cpp-util.hh diff --git a/src/native-clr/include/shared/helpers.hh b/src/native/clr/include/shared/helpers.hh similarity index 100% rename from src/native-clr/include/shared/helpers.hh rename to src/native/clr/include/shared/helpers.hh diff --git a/src/native-clr/include/shared/log_level.hh b/src/native/clr/include/shared/log_level.hh similarity index 100% rename from src/native-clr/include/shared/log_level.hh rename to src/native/clr/include/shared/log_level.hh diff --git a/src/native/clr/include/shared/log_types.hh b/src/native/clr/include/shared/log_types.hh index 0821ef59077..656146ec203 100644 --- a/src/native/clr/include/shared/log_types.hh +++ b/src/native/clr/include/shared/log_types.hh @@ -6,7 +6,7 @@ #include #include "java-interop-logger.h" -#include +#include "log_level.hh" // We redeclare macros here #if defined(log_debug) diff --git a/src/native-clr/include/shared/xxhash.hh b/src/native/clr/include/shared/xxhash.hh similarity index 100% rename from src/native-clr/include/shared/xxhash.hh rename to src/native/clr/include/shared/xxhash.hh diff --git a/src/native/clr/include/startup/zip.hh b/src/native/clr/include/startup/zip.hh index 0c846f50eb8..96afac707bd 100644 --- a/src/native/clr/include/startup/zip.hh +++ b/src/native/clr/include/startup/zip.hh @@ -2,114 +2,30 @@ #include -#include #include #include #include -#include namespace xamarin::android { - namespace detail { - template - concept ByteArrayContainer = requires (T a) { - a.size (); - a.data (); - requires std::same_as; - }; - } - class Zip { - public: - // Returns `true` if the entry was something we need. - using ScanCallbackFn = bool(std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size); - - struct zip_scan_state - { - int file_fd; - std::string_view const& file_name; - const char * const prefix; - uint32_t prefix_len; - size_t buf_offset; - uint16_t compression_method; - uint32_t local_header_offset; - uint32_t data_offset; - uint32_t file_size; - bool bundled_assemblies_slow_path; - uint32_t max_assembly_name_size; - uint32_t max_assembly_file_name_size; - }; - private: - static inline constexpr off_t ZIP_EOCD_LEN = 22; - static inline constexpr off_t ZIP_CENTRAL_LEN = 46; - static inline constexpr off_t ZIP_LOCAL_LEN = 30; + static inline constexpr off_t ZIP_EOCD_LEN = 22; + static inline constexpr off_t ZIP_CENTRAL_LEN = 46; + static inline constexpr off_t ZIP_LOCAL_LEN = 30; static inline constexpr std::string_view ZIP_CENTRAL_MAGIC { "PK\1\2" }; static inline constexpr std::string_view ZIP_LOCAL_MAGIC { "PK\3\4" }; - static inline constexpr std::string_view ZIP_EOCD_MAGIC { "PK\5\6" }; + static inline constexpr std::string_view ZIP_EOCD_MAGIC { "PK\5\6" }; - static constexpr std::string_view zip_path_separator { "/" }; - static constexpr std::string_view apk_lib_dir_name { "lib" }; + static constexpr std::string_view zip_path_separator { "/" }; + static constexpr std::string_view apk_lib_dir_name { "lib" }; - static constexpr size_t lib_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); - static constexpr auto lib_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); + static constexpr size_t assemblies_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); + static constexpr auto assemblies_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view lib_prefix { lib_prefix_array.data () }; - - static constexpr std::string_view dso_suffix { ".so" }; - - static constexpr std::string_view assembly_store_prefix { "libassemblies." }; - static constexpr std::string_view assembly_store_extension { ".blob" }; - - static constexpr size_t assembly_store_file_name_size = calc_size (assembly_store_prefix, Constants::android_lib_abi, assembly_store_extension, dso_suffix); - static constexpr auto assembly_store_file_name_array = concat_string_views (assembly_store_prefix, Constants::android_lib_abi, assembly_store_extension, dso_suffix); - - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array.data () }; - - static constexpr size_t assembly_store_file_path_size = calc_size(lib_prefix, assembly_store_file_name); - static constexpr auto assembly_store_file_path_array = concat_string_views (lib_prefix, assembly_store_file_name); - - public: - // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array.data () }; - - public: - // Scans the ZIP archive for any entries matching the `lib/{ARCH}/` prefix and calls `entry_cb` - // for each of them. If the callback returns `false` for all of the entries (meaning none of them - // was interesting/useful), then the APK file descriptor is closed. Otherwise, the descriptor is - // kept open since we will need it later on. - static void scan_archive (std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept; - - private: - static std::tuple get_assemblies_prefix_and_length () noexcept; - - // Returns `true` if the APK fd needs to remain open. - static bool zip_scan_entries (int apk_fd, std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept; - static bool zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; - static bool zip_read_entry_info (std::vector const& buf, dynamic_local_string& file_name, zip_scan_state &state) noexcept; - static bool zip_load_entry_common (size_t entry_index, std::vector const& buf, dynamic_local_string &entry_name, zip_scan_state &state) noexcept; - static bool zip_adjust_data_offset (int fd, zip_scan_state &state) noexcept; - - template - static bool zip_extract_cd_info (std::array const& buf, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; - - template - static bool zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept; - - template - static bool zip_read_field (T const& src, size_t source_index, uint16_t& dst) noexcept; - - template - static bool zip_read_field (T const& src, size_t source_index, uint32_t& dst) noexcept; - - template - static bool zip_read_field (T const& src, size_t source_index, std::array& dst_sig) noexcept; - - template - static bool zip_read_field (T const& buf, size_t index, size_t count, dynamic_local_string& characters) noexcept; + static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; }; } diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index c65896eb93b..bcf6287c233 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -4,9 +4,8 @@ #include #include -#include -#include +#include "shared/xxhash.hh" static constexpr uint64_t FORMAT_TAG = 0x00035E6972616D58; // 'Xmari^XY' where XY is the format version static constexpr uint32_t COMPRESSED_DATA_MAGIC = 0x5A4C4158; // 'XALZ', little-endian @@ -223,9 +222,9 @@ struct ApplicationConfig { bool uses_assembly_preload; bool jni_add_native_method_registration_attribute_present; + bool have_runtime_config_blob; bool marshal_methods_enabled; bool ignore_split_configs; - uint32_t number_of_runtime_properties; uint32_t package_naming_policy; uint32_t environment_variable_count; uint32_t system_property_count; @@ -242,19 +241,6 @@ struct ApplicationConfig const char *android_package_name; }; -struct RuntimeProperty -{ - const char *key; - const char *value; - uint32_t value_size; // including the terminating NUL -}; - -struct RuntimePropertyIndexEntry -{ - xamarin::android::hash_t key_hash; - uint32_t index; -}; - struct DSOApkEntry { uint64_t name_hash; @@ -337,11 +323,6 @@ extern "C" { [[gnu::visibility("default")]] extern DSOCacheEntry dso_cache[]; [[gnu::visibility("default")]] extern DSOCacheEntry aot_dso_cache[]; [[gnu::visibility("default")]] extern DSOApkEntry dso_apk_entries[]; - - [[gnu::visibility("default")]] extern const RuntimeProperty runtime_properties[]; - [[gnu::visibility("default")]] extern const RuntimePropertyIndexEntry runtime_property_index[]; - - [[gnu::visibility("default")]] extern const host_configuration_properties host_config_properties; } // diff --git a/src/native/clr/runtime-base/CMakeLists.txt b/src/native/clr/runtime-base/CMakeLists.txt index 93f83fea5a7..462a62e36dc 100644 --- a/src/native/clr/runtime-base/CMakeLists.txt +++ b/src/native/clr/runtime-base/CMakeLists.txt @@ -1,57 +1,8 @@ -# First generate some code - -# -# Must be the same value as DSOWrapperGenerator.PayloadSectionAlignment in src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs -# -set(ARCHIVE_DSO_STUB_PAYLOAD_SECTION_ALIGNMENT 0x4000) - -file(COPY "${XA_ARCHIVE_STUB_OUTPUT_DIRECTORY}/${ARCHIVE_DSO_STUB_LIB_FILE_NAME}" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -set(ARCHIVE_DSO_STUB_LIB_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_DSO_STUB_LIB_FILE_NAME}") - -# Emulate what we do when embedding something inside the ELF file -set(PAYLOAD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt) - -execute_process( - COMMAND ${CMAKE_OBJCOPY} --add-section payload=${PAYLOAD_PATH} ${ARCHIVE_DSO_STUB_LIB_PATH} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ECHO_ERROR_VARIABLE - COMMAND_ERROR_IS_FATAL ANY -) - -execute_process( - COMMAND ${CMAKE_OBJCOPY} --set-section-flags payload=readonly,data --set-section-alignment payload=${ARCHIVE_DSO_STUB_PAYLOAD_SECTION_ALIGNMENT} ${ARCHIVE_DSO_STUB_LIB_PATH} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ECHO_ERROR_VARIABLE - COMMAND_ERROR_IS_FATAL ANY -) - -execute_process( - COMMAND ${CMAKE_READELF} --file-header --section-headers ${ARCHIVE_DSO_STUB_LIB_PATH} --elf-output-style=JSON - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - OUTPUT_VARIABLE ARCHIVE_DSO_STUB_HEADER_JSON - ECHO_ERROR_VARIABLE - COMMAND_ERROR_IS_FATAL ANY -) -string(JSON SECTION_HEADER_ENTRY_SIZE GET "${ARCHIVE_DSO_STUB_HEADER_JSON}" 0 "ElfHeader" "SectionHeaderEntrySize") -string(JSON SECTION_HEADER_ENTRY_COUNT GET "${ARCHIVE_DSO_STUB_HEADER_JSON}" 0 "ElfHeader" "SectionHeaderCount") - -math(EXPR PAYLOAD_SECTION_INDEX "${SECTION_HEADER_ENTRY_COUNT} - 1") -string(JSON PAYLOAD_SECTION_OFFSET GET "${ARCHIVE_DSO_STUB_HEADER_JSON}" 0 "Sections" ${PAYLOAD_SECTION_INDEX} "Section" "Offset") -file(REMOVE ${ARCHIVE_DSO_STUB_LIB_PATH}) - -message(STATUS "Archive DSO stub header entry size: ${SECTION_HEADER_ENTRY_SIZE}; section count: ${SECTION_HEADER_ENTRY_COUNT}; payload offset: ${PAYLOAD_SECTION_OFFSET}") -configure_file( - archive-dso-stub-config.hh.in - ${CMAKE_CURRENT_BINARY_DIR}/include/archive-dso-stub-config.hh - USE_SOURCE_PERMISSIONS -) - set(LIB_NAME runtime-base) -set(LIB_ALIAS xa::runtime-base) +set(LIB_ALIAS xa::runtime-base-clr) set(XA_RUNTIME_BASE_SOURCES android-system.cc - cpu-arch-detect.cc logger.cc timing.cc timing-internal.cc @@ -83,12 +34,6 @@ target_compile_options( ${RUNTIME_BASE_CXX_ARGS} ) -target_include_directories( - ${LIB_NAME} - PUBLIC - "$" -) - target_include_directories( ${LIB_NAME} SYSTEM PRIVATE @@ -98,8 +43,8 @@ target_include_directories( target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared - xa::xamarin-app + xa::shared-clr + xa::xamarin-app-clr ) xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index cd3a15d4495..7946cc30580 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -1,19 +1,13 @@ #include #include -#include -#include - #include #include #include -#include #include #include -using namespace microsoft::java_interop; using namespace xamarin::android; - using std::operator""sv; #if defined(DEBUG) @@ -146,80 +140,6 @@ AndroidSystem::setup_environment_from_override_file (dynamic_local_string 0, "At least a single application lib directory must be added"); - app_lib_directories = app_lib_directories.subspan (0, number_of_added_directories); -} - -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"sv); - - app_lib_directories = std::span (single_app_lib_directory); - app_lib_directories [0] = std::string (appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: {}", app_lib_directories [0]); - return; - } - - log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); - 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 = runtimeApks.get_length (); - AndroidSystem::app_lib_directories = std::span (new std::string[app_lib_directories_size], app_lib_directories_size); - } - - uint16_t built_for_cpu = 0, running_on_cpu = 0; - bool is64bit = false; - _monodroid_detect_cpu_and_architecture (built_for_cpu, running_on_cpu, is64bit); - setup_apk_directories (running_on_cpu, runtimeApks, have_split_apks); -} - void AndroidSystem::setup_environment () noexcept { @@ -241,7 +161,7 @@ AndroidSystem::setup_environment () noexcept var_value = ""; } - if constexpr (Constants::is_debug_build) { + if constexpr (Constants::IsDebugBuild) { log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); } @@ -408,86 +328,3 @@ AndroidSystem::get_max_gref_count_from_system () noexcept -> long return max; } - -auto AndroidSystem::get_full_dso_path (std::string const& base_dir, const char *dso_path, dynamic_local_string& path) noexcept -> bool -{ - if (dso_path == nullptr) { - return false; - } - - if (base_dir.empty () || 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 (base_dir) - .append ("/"sv) - .append_c (dso_path); - - return true; -} - -auto AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check) noexcept -> void* -{ - if (path == nullptr || *path == '\0') { - return nullptr; - } - - log_info (LOG_ASSEMBLY, "Trying to load shared library '{}'", path); - if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { - log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); - return nullptr; - } - - char *error = nullptr; - void *handle = java_interop_lib_load (path, dl_flags, &error); - if (handle == nullptr && Util::should_log (LOG_ASSEMBLY)) { - log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '{}'. {}", path, error); - } - java_interop_free (error); - return handle; -} - -template [[gnu::always_inline]] // TODO: replace with a concept -auto AndroidSystem::load_dso_from_specified_dirs (TContainer directories, const char *dso_name, unsigned int dl_flags) noexcept -> void* -{ - if (dso_name == nullptr) { - return nullptr; - } - - dynamic_local_string full_path; - for (std::string const& dir : directories) { - if (!get_full_dso_path (dir, dso_name, full_path)) { - continue; - } - - void *handle = load_dso (full_path.get (), dl_flags, false); - if (handle != nullptr) { - return handle; - } - } - - return nullptr; -} - -auto AndroidSystem::load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags) noexcept -> void* -{ - return load_dso_from_specified_dirs (app_lib_directories, name, dl_flags); -} - -auto AndroidSystem::load_dso_from_override_dirs (const char *name, unsigned int dl_flags) noexcept -> void* -{ - if constexpr (Constants::is_release_build) { - return nullptr; - } else { - return load_dso_from_specified_dirs (AndroidSystem::override_dirs, name, dl_flags); - } -} - -[[gnu::flatten]] -auto AndroidSystem::load_dso_from_any_directories (const char *name, unsigned int dl_flags) noexcept -> void* -{ - void *handle = load_dso_from_override_dirs (name, dl_flags); - if (handle == nullptr) { - handle = load_dso_from_app_lib_dirs (name, dl_flags); - } - return handle; -} diff --git a/src/native/clr/shared/CMakeLists.txt b/src/native/clr/shared/CMakeLists.txt index aa6062066a6..c1a85951663 100644 --- a/src/native/clr/shared/CMakeLists.txt +++ b/src/native/clr/shared/CMakeLists.txt @@ -1,5 +1,5 @@ set(LIB_NAME xa-shared-bits) -set(LIB_ALIAS xa::shared) +set(LIB_ALIAS xa::shared-clr) set(XA_SHARED_SOURCES helpers.cc @@ -27,7 +27,7 @@ macro(lib_target_options TARGET_NAME) target_link_libraries( ${TARGET_NAME} PUBLIC - xa::java-interop + xa::java-interop-clr -llog ) diff --git a/src/native/clr/shared/helpers.cc b/src/native/clr/shared/helpers.cc index 7850592af5a..59697e7d257 100644 --- a/src/native/clr/shared/helpers.cc +++ b/src/native/clr/shared/helpers.cc @@ -35,7 +35,7 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - "Abort at {}:{}:{} ('{}')", + "Abort at {}:{}:{} ('%s')", file_name, sloc.line (), sloc.column (), diff --git a/src/native/clr/startup/CMakeLists.txt b/src/native/clr/startup/CMakeLists.txt index 48600e115e8..2f6951c6275 100644 --- a/src/native/clr/startup/CMakeLists.txt +++ b/src/native/clr/startup/CMakeLists.txt @@ -1,5 +1,5 @@ set(LIB_NAME xamarin-startup) -set(LIB_ALIAS xa::xamarin-startup) +set(LIB_ALIAS xa::xamarin-startup-clr) set(XAMARIN_STARTUP_SOURCES zip.cc @@ -32,7 +32,7 @@ target_compile_options( target_link_directories( ${LIB_NAME} PRIVATE - ${NET_RUNTIME_DIR}/native + ${NET_RUNTIME_DIR}/native-clr ) target_link_options( @@ -45,7 +45,7 @@ target_link_options( target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared + xa::shared-clr -llog ) diff --git a/src/native/clr/startup/zip.cc b/src/native/clr/startup/zip.cc index 0c5413fb2d6..cef57b26618 100644 --- a/src/native/clr/startup/zip.cc +++ b/src/native/clr/startup/zip.cc @@ -1,488 +1,3 @@ -#include - -#include -#include -#include -#include - -#include -#include #include -#include using namespace xamarin::android; - -[[gnu::always_inline]] -std::tuple Zip::get_assemblies_prefix_and_length () noexcept -{ - return {lib_prefix.data (), lib_prefix.size () }; -} - -[[gnu::always_inline]] -bool Zip::zip_adjust_data_offset (int fd, zip_scan_state &state) noexcept -{ - static constexpr size_t LH_FILE_NAME_LENGTH_OFFSET = 26uz; - static constexpr size_t LH_EXTRA_LENGTH_OFFSET = 28uz; - - off_t result = ::lseek (fd, static_cast(state.local_header_offset), SEEK_SET); - if (result < 0) { - log_error ( - LOG_ASSEMBLY, - "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", - state.local_header_offset, std::strerror (errno), result, errno - ); - return false; - } - - std::array local_header; - std::array signature; - - ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); - if (nread < 0 || nread != ZIP_LOCAL_LEN) { - log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); - return false; - } - - size_t index = 0; - if (!zip_read_field (local_header, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); - return false; - } - - if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); - return false; - } - - uint16_t file_name_length; - index = LH_FILE_NAME_LENGTH_OFFSET; - if (!zip_read_field (local_header, index, file_name_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); - return false; - } - - uint16_t extra_field_length; - index = LH_EXTRA_LENGTH_OFFSET; - if (!zip_read_field (local_header, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); - return false; - } - - state.data_offset = static_cast(state.local_header_offset) + file_name_length + extra_field_length + local_header.size (); - - return true; -} - -[[gnu::always_inline]] -bool Zip::zip_read_entry_info (std::vector const& buf, dynamic_local_string& file_name, zip_scan_state &state) noexcept -{ - constexpr size_t CD_COMPRESSION_METHOD_OFFSET = 10uz; - constexpr size_t CD_UNCOMPRESSED_SIZE_OFFSET = 24uz; - constexpr size_t CD_FILENAME_LENGTH_OFFSET = 28uz; - constexpr size_t CD_EXTRA_LENGTH_OFFSET = 30uz; - constexpr size_t CD_LOCAL_HEADER_POS_OFFSET = 42uz; - constexpr size_t CD_COMMENT_LENGTH_OFFSET = 32uz; - - size_t index = state.buf_offset; - zip_ensure_valid_params (buf, index, ZIP_CENTRAL_LEN); - - std::array signature; - if (!zip_read_field (buf, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry signature"sv); - return false; - } - - if (memcmp (signature.data (), ZIP_CENTRAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, "Invalid Central Directory entry signature"sv); - return false; - } - - index = state.buf_offset + CD_COMPRESSION_METHOD_OFFSET; - if (!zip_read_field (buf, index, state.compression_method)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'compression method' field"sv); - return false; - } - - index = state.buf_offset + CD_UNCOMPRESSED_SIZE_OFFSET;; - if (!zip_read_field (buf, index, state.file_size)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'uncompressed size' field"sv); - return false; - } - - uint16_t file_name_length; - index = state.buf_offset + CD_FILENAME_LENGTH_OFFSET; - if (!zip_read_field (buf, index, file_name_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'file name length' field"sv); - return false; - } - - uint16_t extra_field_length; - index = state.buf_offset + CD_EXTRA_LENGTH_OFFSET; - if (!zip_read_field (buf, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'extra field length' field"sv); - return false; - } - - uint16_t comment_length; - index = state.buf_offset + CD_COMMENT_LENGTH_OFFSET; - if (!zip_read_field (buf, index, comment_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'file comment length' field"sv); - return false; - } - - index = state.buf_offset + CD_LOCAL_HEADER_POS_OFFSET; - if (!zip_read_field (buf, index, state.local_header_offset)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'relative offset of local header' field"sv); - return false; - } - index += sizeof(state.local_header_offset); - - if (file_name_length == 0) { - file_name.clear (); - } else if (!zip_read_field (buf, index, file_name_length, file_name)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'file name' field"sv); - return false; - } - - state.buf_offset += ZIP_CENTRAL_LEN + file_name_length + extra_field_length + comment_length; - return true; -} - -bool Zip::zip_load_entry_common (size_t entry_index, std::vector const& buf, dynamic_local_string &entry_name, zip_scan_state &state) noexcept -{ - entry_name.clear (); - - bool result = zip_read_entry_info (buf, entry_name, state); - - log_debug (LOG_ASSEMBLY, "{} entry: {}", state.file_name, optional_string (entry_name.get (), "unknown")); - if (!result || entry_name.empty ()) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Failed to read Central Directory info for entry {} in APK {}", - entry_index, - state.file_name - ) - ); - } - - if (!zip_adjust_data_offset (state.file_fd, state)) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Failed to adjust data start offset for entry {} in APK {}", - entry_index, - state.file_name - ) - ); - } - - log_debug (LOG_ASSEMBLY, " ZIP: local header offset: {}; data offset: {}; file size: {}", state.local_header_offset, state.data_offset, state.file_size); - if (state.compression_method != 0) { - return false; - } - - if (entry_name.get ()[0] != state.prefix[0] || entry_name.length () < state.prefix_len || memcmp (state.prefix, entry_name.get (), state.prefix_len) != 0) { - // state.prefix and lib_prefix can point to the same location, see get_assemblies_prefix_and_length() - // In such instance we short-circuit and avoid a couple of comparisons below. - if (state.prefix == lib_prefix.data ()) { - return false; - } - - if (entry_name.get ()[0] != lib_prefix[0] || memcmp (lib_prefix.data (), entry_name.get (), lib_prefix.size () - 1) != 0) { - return false; - } - } - - // assemblies must be 16-byte or 4-byte aligned, or Bad Things happen - if (((state.data_offset & 0xf) != 0) || ((state.data_offset & 0x3) != 0)) { - std::string_view::size_type pos = state.file_name.find_last_of ('/'); - if (pos == state.file_name.npos) { - pos = 0; - } else { - pos++; - } - std::string_view const& name_no_path = state.file_name.substr (pos); - - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Assembly '{}' is at bad offset {} in the APK (not aligned to 4 or 16 bytes). 'zipalign' MUST be used on {} to align it properly", - optional_string (entry_name.get ()), - state.data_offset, - name_no_path - ) - ); - } - - return true; -} - -template [[gnu::always_inline]] -bool Zip::zip_extract_cd_info (std::array const& buf, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept -{ - constexpr size_t EOCD_TOTAL_ENTRIES_OFFSET = 10uz; - constexpr size_t EOCD_CD_SIZE_OFFSET = 12uz; - constexpr size_t EOCD_CD_START_OFFSET = 16uz; - - static_assert (BufSize >= ZIP_EOCD_LEN, "Buffer too short for EOCD"); - - if (!zip_read_field (buf, EOCD_TOTAL_ENTRIES_OFFSET, cd_entries)) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD 'total number of entries' field"sv); - return false; - } - - if (!zip_read_field (buf, EOCD_CD_START_OFFSET, cd_offset)) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD 'central directory size' field"sv); - return false; - } - - if (!zip_read_field (buf, EOCD_CD_SIZE_OFFSET, cd_size)) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD 'central directory offset' field"sv); - return false; - } - - return true; -} - -template [[gnu::always_inline]] -bool Zip::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept -{ - if (index + to_read > buf.size ()) { - log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); - return false; - } - - return true; -} - -template [[gnu::always_inline]] -bool Zip::zip_read_field (T const& src, size_t source_index, uint16_t& dst) noexcept -{ - if (!zip_ensure_valid_params (src, source_index, sizeof (dst))) { - return false; - } - - dst = static_cast((src [source_index + 1] << 8) | src [source_index]); - return true; -} - -template [[gnu::always_inline]] -bool Zip::zip_read_field (T const& src, size_t source_index, uint32_t& dst) noexcept -{ - if (!zip_ensure_valid_params (src, source_index, sizeof (dst))) { - return false; - } - - dst = - (static_cast (src [source_index + 3]) << 24) | - (static_cast (src [source_index + 2]) << 16) | - (static_cast (src [source_index + 1]) << 8) | - (static_cast (src [source_index + 0])); - - return true; -} - -template [[gnu::always_inline]] -bool Zip::zip_read_field (T const& src, size_t source_index, std::array& dst_sig) noexcept -{ - if (!zip_ensure_valid_params (src, source_index, dst_sig.size ())) { - return false; - } - - memcpy (dst_sig.data (), src.data () + source_index, dst_sig.size ()); - return true; -} - -template [[gnu::always_inline]] -bool Zip::zip_read_field (T const& buf, size_t index, size_t count, dynamic_local_string& characters) noexcept -{ - if (!zip_ensure_valid_params (buf, index, count)) { - return false; - } - - characters.assign (reinterpret_cast(buf.data () + index), count); - return true; -} - -[[gnu::always_inline]] -bool Zip::zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept -{ - // The simplest case - no file comment - off_t ret = ::lseek (apk_fd, -ZIP_EOCD_LEN, SEEK_END); - if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); - return false; - } - - std::array eocd; - ssize_t nread = ::read (apk_fd, eocd.data (), eocd.size ()); - if (nread < 0 || nread != eocd.size ()) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); - return false; - } - - size_t index = 0uz; // signature - std::array signature; - - if (!zip_read_field (eocd, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD signature"sv); - return false; - } - - if (memcmp (signature.data (), ZIP_EOCD_MAGIC.data (), signature.size ()) == 0) { - return zip_extract_cd_info (eocd, cd_offset, cd_size, cd_entries); - } - - // Most probably a ZIP with comment - constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed - ret = ::lseek (apk_fd, static_cast(-alloc_size), SEEK_END); - if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); - return false; - } - - std::vector buf (alloc_size); - - nread = ::read (apk_fd, buf.data (), buf.size ()); - - if (nread < 0 || static_cast(nread) != alloc_size) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); - return false; - } - - // We scan from the end to save time - bool found = false; - const uint8_t* data = buf.data (); - for (ssize_t i = static_cast(alloc_size - (ZIP_EOCD_LEN + 2)); i >= 0z; i--) { - if (memcmp (data + i, ZIP_EOCD_MAGIC.data (), sizeof(ZIP_EOCD_MAGIC)) != 0) - continue; - - found = true; - memcpy (eocd.data (), data + i, ZIP_EOCD_LEN); - break; - } - - if (!found) { - log_error (LOG_ASSEMBLY, "Unable to find EOCD in the APK (with comment)"sv); - return false; - } - - return zip_extract_cd_info (eocd, cd_offset, cd_size, cd_entries); -} - -[[gnu::always_inline]] -bool Zip::zip_scan_entries (int apk_fd, std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept -{ - uint32_t cd_offset; - uint32_t cd_size; - uint16_t cd_entries; - - if (!zip_read_cd_info (apk_fd, cd_offset, cd_size, cd_entries)) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Failed to read the EOCD record from APK file %s", - apk_path - ) - ); - } - - log_debug (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); - log_debug (LOG_ASSEMBLY, "Central directory size: {}", cd_size); - log_debug (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); - - off_t retval = ::lseek (apk_fd, static_cast(cd_offset), SEEK_SET); - if (retval < 0) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Failed to seek to central directory position in APK: {}. retval={} errno={}, File={}", - std::strerror (errno), - retval, - errno, - apk_path - ) - ); - } - - std::vector buf (cd_size); - const auto [prefix, prefix_len] = get_assemblies_prefix_and_length (); - zip_scan_state state { - .file_fd = apk_fd, - .file_name = apk_path, - .prefix = prefix, - .prefix_len = prefix_len, - .buf_offset = 0uz, - .compression_method = 0u, - .local_header_offset = 0u, - .data_offset = 0u, - .file_size = 0u, - .bundled_assemblies_slow_path = false, - .max_assembly_name_size = 0u, - .max_assembly_file_name_size = 0u, - }; - - ssize_t nread; - do { - nread = read (apk_fd, buf.data (), buf.size ()); - } while (nread < 0 && errno == EINTR); - - if (static_cast(nread) != cd_size) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Failed to read Central Directory from APK: {}. nread={} errno={} File={}", - std::strerror (errno), - nread, - errno, - apk_path - ) - ); - } - - dynamic_local_string entry_name; - bool keep_archive_open = false; - - for (size_t i = 0uz; i < cd_entries; i++) { - bool interesting_entry = zip_load_entry_common (i, buf, entry_name, state); - if (!interesting_entry) { - continue; - } - - keep_archive_open |= entry_cb (apk_path, apk_fd, entry_name, state.data_offset, state.file_size); - } - - return keep_archive_open; -} - -void Zip::scan_archive (std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept -{ - int fd; - do { - fd = open (apk_path.data (), O_RDONLY); - } while (fd < 0 && errno == EINTR); - - if (fd < 0) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "ERROR: Unable to load application package {}. {}", - apk_path, strerror (errno) - ) - ); - } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", apk_path, fd); - if (!zip_scan_entries (fd, apk_path, entry_cb)) { - return; - } - - if (close (fd) < 0) { - log_warn ( - LOG_ASSEMBLY, - "Failed to close file descriptor for {}. {}", - apk_path, - strerror (errno) - ); - } -} diff --git a/src/native/clr/xamarin-app-stub/CMakeLists.txt b/src/native/clr/xamarin-app-stub/CMakeLists.txt index c883ce2a2cb..d23328f9ce7 100644 --- a/src/native/clr/xamarin-app-stub/CMakeLists.txt +++ b/src/native/clr/xamarin-app-stub/CMakeLists.txt @@ -1,5 +1,5 @@ -set(LIB_NAME xamarin-app) -set(LIB_ALIAS xa::xamarin-app) +set(LIB_NAME xamarin-app-clr) +set(LIB_ALIAS xa::xamarin-app-clr) set(XAMARIN_APP_SOURCES application_dso_stub.cc diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 0e355298d40..2a34ff4c13d 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -44,16 +44,15 @@ constexpr char android_package_name[] = "com.xamarin.test"; const ApplicationConfig application_config = { .uses_assembly_preload = false, .jni_add_native_method_registration_attribute_present = false, + .have_runtime_config_blob = false, .marshal_methods_enabled = false, .ignore_split_configs = false, - .number_of_runtime_properties = 3, .package_naming_policy = 0, .environment_variable_count = 0, .system_property_count = 0, .number_of_assemblies_in_apk = 2, .bundled_assembly_name_width = 0, .number_of_dso_cache_entries = 2, - .number_of_aot_cache_entries = 2, .number_of_shared_libraries = 2, .android_runtime_jnienv_class_token = 1, .jnienv_initialize_method_token = 2, @@ -297,68 +296,3 @@ const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[] = { .replacement = "another/replacement/java/type", }, }; - -constexpr char prop_test_string_key[] = "test_string"; -constexpr char prop_test_integer_key[] = "test_integer"; -constexpr char prop_test_boolean_key[] = "test_boolean"; - -const RuntimeProperty runtime_properties[] = { - { - .key = prop_test_string_key, - .value = "test", - .value_size = sizeof("test"), - }, - - { - .key = prop_test_integer_key, - .value = "42", - .value_size = sizeof("42"), - }, - - { - .key = prop_test_boolean_key, - .value = "true", - .value_size = sizeof("true"), - }, -}; - -const RuntimePropertyIndexEntry runtime_property_index[] = { - { - .key_hash = xamarin::android::xxhash::hash (prop_test_string_key, sizeof(prop_test_string_key) - 1), - .index = 0, - }, - - { - .key_hash = xamarin::android::xxhash::hash (prop_test_integer_key, sizeof(prop_test_integer_key) - 1), - .index = 1, - }, - - { - .key_hash = xamarin::android::xxhash::hash (prop_test_boolean_key, sizeof(prop_test_boolean_key) - 1), - .index = 2, - }, -}; - -namespace { - const host_configuration_property _host_configuration_properties_data[] = { - { - .name = u"test_string", - .value = u"string value", - }, - - { - .name = u"test_integer", - .value = u"23", - }, - - { - .name = u"test_boolean", - .value = u"true", - }, - }; -} - -const host_configuration_properties host_config_properties = { - .nitems = 3, - .data = _host_configuration_properties_data, -}; diff --git a/src/native/libmono-android.map.txt b/src/native/mono/monolibmono-android.map.txt similarity index 100% rename from src/native/libmono-android.map.txt rename to src/native/mono/monolibmono-android.map.txt diff --git a/src/native/mono/runtime-base/jni-wrappers.hh b/src/native/mono/runtime-base/jni-wrappers.hh new file mode 100644 index 00000000000..679aed3df59 --- /dev/null +++ b/src/native/mono/runtime-base/jni-wrappers.hh @@ -0,0 +1,209 @@ +#pragma once + +#include + +#include + +#include + +namespace xamarin::android +{ + class jstring_array_wrapper; + + class jstring_wrapper + { + public: + explicit jstring_wrapper (JNIEnv *_env) noexcept + : env (_env), + jstr (nullptr) + { + abort_if_invalid_pointer_argument (_env, "_env"); + } + + explicit jstring_wrapper (JNIEnv *_env, const jobject jo) noexcept + : env (_env), + jstr (reinterpret_cast (jo)) + { + abort_if_invalid_pointer_argument (_env, "_env"); + } + + explicit jstring_wrapper (JNIEnv *_env, const jstring js) noexcept + : env (_env), + jstr (js) + { + abort_if_invalid_pointer_argument (_env, "_env"); + } + + jstring_wrapper (const jstring_wrapper&) = delete; + + ~jstring_wrapper () noexcept + { + release (); + } + + jstring_wrapper& operator=(const jstring_wrapper&) = delete; + + bool hasValue () noexcept + { + return jstr != nullptr; + } + + private: + [[gnu::always_inline]] + void ensure_cstr () noexcept + { + if (cstr != nullptr || env == nullptr) { + return; + } + + cstr = env->GetStringUTFChars (jstr, nullptr); + } + + public: + const char* get_cstr () noexcept + { + if (jstr == nullptr) { + return nullptr; + } + + ensure_cstr (); + return cstr; + } + + [[gnu::always_inline]] + const std::string_view get_string_view () noexcept + { + if (jstr == nullptr) { + return {}; + } + + ensure_cstr (); + return {cstr}; + } + + jstring_wrapper& operator= (const jobject new_jo) noexcept + { + assign (reinterpret_cast (new_jo)); + return *this; + } + + jstring_wrapper& operator= (const jstring new_js) noexcept + { + assign (new_js); + return *this; + } + + protected: + void release () noexcept + { + if (jstr == nullptr || cstr == nullptr || env == nullptr) { + return; + } + env->ReleaseStringUTFChars (jstr, cstr); + jobjectRefType type = env->GetObjectRefType (jstr); + switch (type) { + case JNILocalRefType: + env->DeleteLocalRef (jstr); + break; + + case JNIGlobalRefType: + env->DeleteGlobalRef (jstr); + break; + + case JNIWeakGlobalRefType: + env->DeleteWeakGlobalRef (jstr); + break; + + case JNIInvalidRefType: // To hush compiler warning + break; + } + + jstr = nullptr; + cstr = nullptr; + } + + void assign (const jstring new_js) noexcept + { + release (); + if (new_js == nullptr) { + return; + } + + jstr = new_js; + cstr = nullptr; + } + + friend class jstring_array_wrapper; + + private: + jstring_wrapper () + : env (nullptr), + jstr (nullptr) + {} + + private: + JNIEnv *env; + jstring jstr; + const char *cstr = nullptr; + }; + + class jstring_array_wrapper + { + public: + explicit jstring_array_wrapper (JNIEnv *_env) noexcept + : jstring_array_wrapper(_env, nullptr) + {} + + explicit jstring_array_wrapper (JNIEnv *_env, jobjectArray _arr) + : env (_env), + arr (_arr) + { + abort_if_invalid_pointer_argument (_env, "_env"); + if (_arr != nullptr) { + len = static_cast(_env->GetArrayLength (_arr)); + if (len > sizeof (static_wrappers) / sizeof (jstring_wrapper)) { + wrappers = new jstring_wrapper [len]; + } else { + wrappers = static_wrappers; + } + } else { + len = 0; + wrappers = nullptr; + } + } + + ~jstring_array_wrapper () noexcept + { + if (wrappers != nullptr && wrappers != static_wrappers) { + delete[] wrappers; + } + } + + size_t get_length () const noexcept + { + return len; + } + + jstring_wrapper& operator[] (size_t index) noexcept + { + if (index >= len) { + return invalid_wrapper; + } + + if (wrappers [index].env == nullptr) { + wrappers [index].env = env; + wrappers [index].jstr = reinterpret_cast (env->GetObjectArrayElement (arr, static_cast(index))); + } + + return wrappers [index]; + } + + private: + JNIEnv *env; + jobjectArray arr; + size_t len; + jstring_wrapper *wrappers; + jstring_wrapper static_wrappers[5]; + jstring_wrapper invalid_wrapper; + }; +} diff --git a/src/native/mono/runtime-base/search.hh b/src/native/mono/runtime-base/search.hh new file mode 100644 index 00000000000..c6c3311795f --- /dev/null +++ b/src/native/mono/runtime-base/search.hh @@ -0,0 +1,60 @@ +// Dear Emacs, this is a -*- C++ -*- header +#pragma once + +#include + +#include + +namespace xamarin::android { + class Search final + { + public: + template + [[gnu::always_inline]] + static ssize_t binary_search (hash_t key, const T *arr, size_t n) noexcept + { + static_assert (equal != nullptr, "equal is a required template parameter"); + static_assert (less_than != nullptr, "less_than is a required template parameter"); + + ssize_t left = -1z; + ssize_t right = static_cast(n); + + while (right - left > 1) { + ssize_t middle = (left + right) >> 1u; + if (less_than (arr[middle], key)) { + left = middle; + } else { + right = middle; + } + } + + return equal (arr[right], key) ? right : -1z; + } + + [[gnu::always_inline]] + static ssize_t binary_search (hash_t key, const hash_t *arr, size_t n) noexcept + { + auto equal = [](hash_t const& entry, hash_t key) -> bool { return entry == key; }; + auto less_than = [](hash_t const& entry, hash_t key) -> bool { return entry < key; }; + + return binary_search (key, arr, n); + } + + [[gnu::always_inline]] + static ptrdiff_t binary_search_branchless (hash_t x, const hash_t *arr, uint32_t len) noexcept + { + const hash_t *base = arr; + while (len > 1) { + uint32_t half = len >> 1; + // __builtin_prefetch(&base[(len - half) / 2]); + // __builtin_prefetch(&base[half + (len - half) / 2]); + base = (base[half] < x ? &base[half] : base); + len -= half; + } + + //return *(base + (*base < x)); + ptrdiff_t ret = (base + (*base < x)) - arr; + return arr[ret] == x ? ret : -1; + } + }; +} diff --git a/src/native/mono/runtime-base/strings.hh b/src/native/mono/runtime-base/strings.hh new file mode 100644 index 00000000000..b076e4f5ca9 --- /dev/null +++ b/src/native/mono/runtime-base/strings.hh @@ -0,0 +1,964 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(XA_HOST_CLR) +#include +#else +#include + +using Constants = xamarin::android::internal::SharedConstants; +#endif + +namespace xamarin::android { + static constexpr size_t SENSIBLE_TYPE_NAME_LENGTH = 128uz; + static constexpr size_t SENSIBLE_PATH_MAX = 256uz; + +#if DEBUG + static constexpr bool BoundsCheck = true; +#else + static constexpr bool BoundsCheck = false; +#endif + + enum class string_segment_error + { + index_out_of_range, + }; + + static inline auto to_string (string_segment_error error) -> std::string_view const + { + using std::operator""sv; + + switch (error) { + case string_segment_error::index_out_of_range: + return "Index out of range"sv; + + default: + return "Unknown error"sv; + } + } + + class string_segment + { + public: + [[gnu::always_inline]] + auto initialized () const noexcept -> bool + { + return !_fresh; + } + + [[gnu::always_inline]] + auto start () const noexcept -> const char* + { + return _start; + } + + [[gnu::always_inline]] + auto at (size_t offset) const noexcept -> std::expected + { + if (offset >= length ()) { + return std::unexpected (string_segment_error::index_out_of_range); + } + + return _start + offset; + } + + [[gnu::always_inline]] + auto length () const noexcept -> size_t + { + return _length; + } + + [[gnu::always_inline]] + auto empty () const noexcept -> bool + { + return length () == 0; + } + + [[gnu::always_inline]] + auto equal (const char *s) const noexcept -> bool + { + if (s == nullptr) { + return false; + } + + return equal (s, strlen (s)); + } + + [[gnu::always_inline]] + auto equal (const char *s, size_t s_length) const noexcept -> bool + { + if (s == nullptr) { + return false; + } + + if (length () != s_length) { + return false; + } + + if (!can_access (s_length)) [[unlikely]] { + return false; + } + + if (length () == 0) { + return true; + } + + return memcmp (_start, s, length ()) == 0; + } + + template [[gnu::always_inline]] + auto equal (const char (&s)[Size]) noexcept -> bool + { + return equal (s, Size - 1); + } + + [[gnu::always_inline]] + auto equal (std::string_view const& s) noexcept -> bool + { + return equal (s.data (), s.length ()); + } + + [[gnu::always_inline]] + auto starts_with_c (const char *s) const noexcept -> bool + { + if (s == nullptr) { + return false; + } + + return starts_with (s, strlen (s)); + } + + [[gnu::always_inline]] + auto starts_with (const char *s, size_t s_length) const noexcept -> bool + { + if (s == nullptr || !can_access (s_length)) { + return false; + } + + if (length () < s_length) { + return false; + } + + return memcmp (start (), s, s_length) == 0; + } + + template [[gnu::always_inline]] + auto starts_with (const char (&s)[Size]) const noexcept -> bool + { + return starts_with (s, Size - 1); + } + + [[gnu::always_inline]] + auto starts_with (std::string_view const& s) const noexcept -> bool + { + return starts_with (s.data (), s.length ()); + } + + [[gnu::always_inline]] + auto has_at (const char ch, size_t index) const noexcept -> bool + { + if (!can_access (index)) { + return false; + } + + return start ()[index] == ch; + } + + [[gnu::always_inline]] + auto find (const char ch, size_t start_index) const noexcept -> ssize_t + { + if (!can_access (start_index)) { + return -1; + } + + while (start_index <= length ()) { + if (start ()[start_index] == ch) { + return static_cast(start_index); + } + start_index++; + } + + return -1; + } + + template [[gnu::always_inline]] + auto to_integer (T &val, size_t start_index = 0uz, int base = 10) const noexcept -> bool + { + static_assert (std::is_integral_v); + constexpr T min = std::numeric_limits::min (); + constexpr T max = std::numeric_limits::max (); + using integer = typename std::conditional, int64_t, uint64_t>::type; + + if (length () == 0uz) { + return false; + } + + if (!can_access (start_index)) { + log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); + return false; + } + + // FIXME: this is less than ideal... we shouldn't need another buffer here + size_t slen = length () - start_index; + char s[slen + 1]; + + memcpy (s, start () + start_index, slen); + s[slen] = '\0'; + + integer ret; + char *endp; + bool out_of_range; + errno = 0; + if constexpr (std::is_signed_v) { + ret = strtoll (s, &endp, base); + out_of_range = ret < min || ret > max; + } else { + ret = strtoull (s, &endp, base); + out_of_range = ret > max; + } + + if (out_of_range || errno == ERANGE) { + log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); + return false; + } + + if (endp == s) { + log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); + return false; + } + + if (*endp != '\0') { + log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); + return false; + } + + val = static_cast(ret); + return true; + } + + private: + [[gnu::always_inline]] + auto can_access (size_t index) const noexcept -> bool + { + if (!initialized () || start () == nullptr) [[unlikely]] { + return false; + } + + if (index > length ()) { + return false; + } + + return true; + } + + protected: + size_t _last_index = 0uz; + bool _fresh = true; + const char *_start = nullptr; + size_t _length = 0uz; + + template friend class string_base; + }; + + template + class local_storage + { + protected: + using LocalStoreArray = std::array; + + public: + static constexpr bool has_resize = HasResize; + + public: + explicit local_storage (size_t size) noexcept + { + static_assert (MaxStackSize > 0, "MaxStackSize must be more than 0"); + init_store (size < MaxStackSize ? MaxStackSize : size); + } + + virtual ~local_storage () + { + free_store (); + } + + auto get () noexcept -> T* + { + return allocated_store == nullptr ? local_store.data () : allocated_store; + } + + auto get () const noexcept -> const T* + { + return allocated_store == nullptr ? local_store.data () : allocated_store; + } + + auto size () const noexcept -> size_t + { + return store_size; + } + + protected: + [[gnu::always_inline]] + void init_store (size_t new_size) noexcept + { + if (new_size > MaxStackSize) { + allocated_store = new T[new_size]; + } else { + allocated_store = nullptr; + } + store_size = new_size; + } + + [[gnu::always_inline]] + void free_store () noexcept + { + if (allocated_store == nullptr) { + return; + } + + delete[] allocated_store; + } + + [[gnu::always_inline]] + auto get_local_store () noexcept -> LocalStoreArray& + { + return local_store; + } + + [[gnu::always_inline]] + auto get_allocated_store () noexcept -> T* + { + return allocated_store; + } + + private: + size_t store_size; + LocalStoreArray local_store; + T* allocated_store; + }; + + // This class is meant to provide a *very* thin veneer (by design) over space allocated for *local* buffers - that + // is one which are not meant to survive the exit of the function they are created in. The idea is that the caller + // knows the size of the buffer they need and they want to put the buffer on stack, if it doesn't exceed a certain + // value, or dynamically allocate memory if more is needed. Even though the class could be used on its own, it's + // really meant to be a base for more specialized buffers. There are not many safeguards, by design - the code is + // meant to be performant. This is the reason why the size is static throughout the life of the object, so that we + // can perform as few checks as possible. + + template using static_local_storage_base = local_storage; + + template + class static_local_storage final : public static_local_storage_base + { + using base = static_local_storage_base; + + public: + explicit static_local_storage (size_t initial_size) noexcept + : base (initial_size) + {} + }; + + template using dynamic_local_storage_base = local_storage; + + template + class dynamic_local_storage final : public dynamic_local_storage_base + { + using base = dynamic_local_storage_base; + + public: + explicit dynamic_local_storage (size_t initial_size = 0uz) noexcept + : base (initial_size) + {} + + // + // If `new_size` is smaller than the current size and the dynamic store is allocated, data WILL NOT be + // preserved. + // + // If `new_size` is bigger than the current size bigger than MaxStackSize, data will be copied to the new + // dynamically allocated store + // + // If `new_size` is smaller or equal to `MaxStackSize`, no changes are made unless dynamic store was allocated, + // in which case it will be freed + // + void resize (size_t new_size) noexcept + { + size_t old_size = base::size (); + + if (new_size == old_size) { + return; + } + + if (new_size <= MaxStackSize) { + new_size = MaxStackSize; + base::free_store (); + return; + } + + if (new_size < old_size) { + base::free_store (); + base::init_store (new_size); + return; + } + + T* old_allocated_store = base::get_allocated_store (); + base::init_store (new_size); + + T* new_allocated_store = base::get_allocated_store (); + if (old_allocated_store != nullptr) { + std::memcpy (new_allocated_store, old_allocated_store, old_size); + delete[] old_allocated_store; + return; + } + + std::memcpy (new_allocated_store, base::get_local_store ().data (), MaxStackSize); + } + }; + + template + class string_base + { + protected: + static constexpr TChar NUL = '\0'; + static constexpr TChar ZERO = '0'; + + public: + explicit string_base (size_t initial_size = 0uz) + : buffer (initial_size) + { + // Currently we care only about `char`, maybe in the future we'll add support for `wchar` (if needed) + static_assert (std::is_same_v, "TChar must be an 8-bit character type"); + + clear (); + } + + explicit string_base (const string_segment &token) + : string_base (token.initialized () ? token.length () : 0) + { + if (token.initialized ()) { + assign (token.start (), token.length ()); + } + } + + [[gnu::always_inline]] + auto length () const noexcept -> size_t + { + return idx; + } + + [[gnu::always_inline]] + auto empty () const noexcept -> bool + { + return length () == 0; + } + + [[gnu::always_inline]] + void set_length (size_t new_length) noexcept + { + if (new_length >= buffer.size ()) { + return; + } + + idx = new_length; + terminate (); + } + + [[gnu::always_inline]] + void clear () noexcept + { + set_length (0); + buffer.get ()[0] = NUL; + } + + [[gnu::always_inline]] + void terminate () noexcept + { + buffer.get ()[idx] = NUL; + } + + [[gnu::always_inline]] + auto replace (const TChar c1, const TChar c2) noexcept -> string_base& + { + if (empty ()) { + return *this; + } + + for (size_t i = 0uz; i < length (); i++) { + if (buffer.get ()[i] == c1) { + buffer.get ()[i] = c2; + } + } + + return *this; + } + + [[gnu::always_inline]] + auto append (const TChar* s, size_t length) noexcept -> string_base& + { + if (s == nullptr || length == 0uz) { + return *this; + } + + resize_for_extra (length); + if constexpr (BoundsCheck) { + ensure_have_extra (length); + } + + std::memcpy (buffer.get () + idx, s, length); + idx += length; + buffer.get ()[idx] = NUL; + + return *this; + } + + template + [[gnu::always_inline]] + auto append (string_base const& str) noexcept -> string_base& + { + return append (str.get (), str.length ()); + } + + [[gnu::always_inline]] + auto append (std::string_view const& sv) noexcept -> string_base& + { + return append (sv.data (), sv.length ()); + } + + template [[gnu::always_inline]] + auto append (const char (&s)[Size]) noexcept -> string_base& + { + return append (s, Size - 1); + } + + [[gnu::always_inline]] + auto append_c (const char *s) noexcept -> string_base& + { + if (s == nullptr) { + return *this; + } + + return append (s, strlen (s)); + } + + [[gnu::always_inline]] + auto append (int16_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (buffer.get (), i); + return *this; + } + + [[gnu::always_inline]] + auto append (uint16_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (int32_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (uint32_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (int64_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto append (uint64_t i) noexcept -> string_base& + { + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + append_integer (i); + return *this; + } + + [[gnu::always_inline]] + auto assign (const TChar* s, size_t length) noexcept -> string_base& + { + idx = 0; + return append (s, length); + } + + [[gnu::always_inline]] + auto assign_c (const TChar* s) noexcept -> string_base& + { + if (s == nullptr) { + return *this; + } + + return assign (s, strlen (s)); + } + + [[gnu::always_inline]] + auto assign (std::string_view const& sv) noexcept -> string_base& + { + return assign (sv.data (), sv.size ()); + } + + [[gnu::always_inline]] + auto assign (std::string const& s) noexcept -> string_base& + { + return assign (s.data (), s.size ()); + } + + template [[gnu::always_inline]] + auto assign (const char (&s)[Size]) noexcept -> string_base& + { + return assign (s, Size - 1); + } + + template + [[gnu::always_inline]] + auto assign (string_base const& str) noexcept -> string_base& + { + return assign (str.get (), str.length ()); + } + + [[gnu::always_inline]] + auto assign (const TChar* s, size_t offset, size_t count) noexcept -> string_base& + { + if (s == nullptr) { + return *this; + } + + if constexpr (BoundsCheck) { + size_t slen = strlen (s); + if (offset + count > slen) { + Helpers::abort_application ("Attempt to assign data from a string exceeds the source string length"); + } + } + + return assign (s + offset, count); + } + + [[gnu::always_inline]] + auto next_token (size_t start_index, const TChar separator, string_segment& token) const noexcept -> bool + { + size_t index; + if (token._fresh) { + token._fresh = false; + token._last_index = start_index; + index = start_index; + } else { + index = token._last_index + 1; + } + + token._start = nullptr; + token._length = 0; + if (token._last_index + 1 >= buffer.size ()) { + return false; + } + + const TChar *start = buffer.get () + index; + const TChar *p = start; + while (*p != NUL) { + if (*p == separator) { + break; + } + p++; + index++; + } + + token._last_index = *p == NUL ? buffer.size () : index; + token._start = start; + token._length = static_cast(p - start); + + return true; + } + + [[gnu::always_inline]] + auto next_token (const char separator, string_segment& token) const noexcept -> bool + { + return next_token (0, separator, token); + } + + [[gnu::always_inline]] + auto index_of (const TChar ch) const noexcept -> ssize_t + { + const TChar *p = buffer.get (); + while (p != nullptr && *p != NUL) { + if (*p == ch) { + return static_cast(p - buffer.get ()); + } + p++; + } + + return -1; + } + + [[gnu::always_inline]] + auto starts_with (const TChar *s, size_t s_length) const noexcept -> bool + { + if (s == nullptr || s_length == 0 || s_length > buffer.size ()) { + return false; + } + + return memcmp (buffer.get (), s, s_length) == 0; + } + + [[gnu::always_inline]] + auto starts_with_c (const char* s) noexcept -> bool + { + if (s == nullptr) { + return false; + } + + return starts_with (s, strlen (s)); + } + + template [[gnu::always_inline]] + auto starts_with (const char (&s)[Size]) noexcept -> bool + { + return starts_with (s, Size - 1); + } + + [[gnu::always_inline]] + auto starts_with (std::string_view const& s) noexcept -> bool + { + return starts_with (s.data (), s.length ()); + } + + [[gnu::always_inline]] + void set_length_after_direct_write (size_t new_length) noexcept + { + set_length (new_length); + terminate (); + } + + [[gnu::always_inline]] + void set_at (size_t index, const TChar ch) noexcept + { + ensure_valid_index (index); + TChar *p = buffer + index; + if (*p == NUL) { + return; + } + + *p = ch; + } + + [[gnu::always_inline]] + auto get_at (size_t index) const noexcept -> const TChar + { + ensure_valid_index (index); + return *(buffer.get () + index); + } + + [[gnu::always_inline]] + auto get_at (size_t index) noexcept -> TChar& + { + ensure_valid_index (index); + return *(buffer.get () + index); + } + + [[gnu::always_inline]] + auto get () const noexcept -> const TChar* + { + return buffer.get (); + } + + [[gnu::always_inline]] + auto get () noexcept -> TChar* + { + return buffer.get (); + } + + [[gnu::always_inline]] + auto size () const noexcept -> size_t + { + return buffer.size (); + } + + [[gnu::always_inline]] + auto operator[] (size_t index) const noexcept -> char + { + return get_at (index); + } + + [[gnu::always_inline]] + auto operator[] (size_t index) noexcept -> char& + { + return get_at (index); + } + + protected: + template [[gnu::always_inline]] + void append_integer (Integer i) noexcept + { + static_assert (std::is_integral_v); + + resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + if constexpr (BoundsCheck) { + ensure_have_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); + } + + if (i == 0) { + constexpr char zero[] = "0"; + constexpr size_t zero_len = sizeof(zero) - 1uz; + + append (zero, zero_len); + return; + } + + TChar temp_buf[Constants::MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz]; + TChar *p = temp_buf + Constants::MAX_INTEGER_DIGIT_COUNT_BASE10; + *p = NUL; + TChar *end = p; + + uint32_t x; + if constexpr (sizeof(Integer) > 4uz) { + uint64_t y; + + if constexpr (std::is_signed_v) { + y = static_cast(i > 0 ? i : -i); + } else { + y = static_cast(i); + } + while (y > std::numeric_limits::max ()) { + *--p = (y % 10) + ZERO; + y /= 10; + } + x = static_cast(y); + } else { + if constexpr (std::is_signed_v) { + x = static_cast(i > 0 ? i : -i); + } else { + x = static_cast(i); + } + } + + while (x > 0) { + *--p = (x % 10) + ZERO; + x /= 10; + } + + if constexpr (std::is_signed_v) { + if (i < 0) + *--p = '-'; + } + + append (p, static_cast(end - p)); + } + + [[gnu::always_inline]] + void ensure_valid_index (size_t access_index) const noexcept + { + if (access_index < idx && access_index < buffer.size ()) [[likely]] { + return; + } + + char *message = nullptr; + int n = asprintf (&message, "Index %zu is out of range (0 - %zu)", access_index, idx); + Helpers::abort_application (n == -1 ? "Index out of range" : message); + } + + [[gnu::always_inline]] + void ensure_have_extra (size_t length) noexcept + { + size_t needed_space = Helpers::add_with_overflow_check (length, idx + 1); + if (needed_space > buffer.size ()) { + char *message = nullptr; + int n = asprintf ( + &message, + "Attempt to store too much data in a buffer (capacity: %zu; exceeded by: %zu)", + buffer.size (), + needed_space - buffer.size () + ); + Helpers::abort_application (n == -1 ? "Attempt to store too much data in a buffer" : message); + } + } + + [[gnu::always_inline]] + void resize_for_extra (size_t needed_space) noexcept + { + if constexpr (TStorage::has_resize) { + size_t required_space = Helpers::add_with_overflow_check (needed_space, idx + 1uz); + size_t current_size = buffer.size (); + if (required_space > current_size) { + size_t new_size = Helpers::add_with_overflow_check (current_size, (current_size / 2uz)); + new_size = Helpers::add_with_overflow_check (new_size, required_space); + buffer.resize (new_size); + } + } + } + + private: + size_t idx; + TStorage buffer; + }; + + template + class static_local_string : public string_base, TChar> + { + using base = string_base, TChar>; + + public: + explicit static_local_string (size_t initial_size = 0uz) noexcept + : base (initial_size) + {} + + explicit static_local_string (const string_segment &token) noexcept + : base (token) + {} + + template + explicit static_local_string (const char (&str)[N]) + : base (N) + { + append (str); + } + }; + + template + class dynamic_local_string : public string_base, TChar> + { + using base = string_base, TChar>; + + public: + explicit dynamic_local_string (size_t initial_size = 0uz) + : base (initial_size) + {} + + explicit dynamic_local_string (const string_segment &token) noexcept + : base (token) + {} + + template + explicit dynamic_local_string (const char (&str)[N]) + : base (N) + { + base::append (str); + } + + explicit dynamic_local_string (std::string_view const& str) + : base (str.length ()) + { + base::append (str); + } + }; +} diff --git a/src/native/mono/shared/helpers.hh b/src/native/mono/shared/helpers.hh new file mode 100644 index 00000000000..587c48a7f76 --- /dev/null +++ b/src/native/mono/shared/helpers.hh @@ -0,0 +1,106 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include "platform-compat.hh" + +using namespace std::string_view_literals; + +namespace xamarin::android +{ + namespace detail { + template + concept TPointer = requires { std::is_pointer_v; }; + } + + class [[gnu::visibility("hidden")]] Helpers + { + public: + template + [[gnu::always_inline]] + static auto add_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret + { + constexpr bool DoNotLogLocation = false; + Ret ret; + + if (__builtin_add_overflow (a, b, &ret)) [[unlikely]] { + // It will leak memory, but it's fine, we're exiting the app anyway + char *message = nullptr; + int n = asprintf (&message, "Integer overflow on addition at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (n == -1 ? "Integer overflow on addition" : message, DoNotLogLocation, sloc); + } + + return ret; + } + + template + [[gnu::always_inline]] + static auto multiply_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret + { + constexpr bool DoNotLogLocation = false; + Ret ret; + + if (__builtin_mul_overflow (a, b, &ret)) [[unlikely]] { + // It will leak memory, but it's fine, we're exiting the app anyway + char *message = nullptr; + int n = asprintf (&message, "Integer overflow on multiplication at %s:%u", sloc.file_name (), sloc.line ()); + abort_application (n == -1 ? "Integer overflow on multiplication" : message, DoNotLogLocation, sloc); + } + + return ret; + } + + [[noreturn]] + static void abort_application (LogCategories category, const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; + + [[noreturn]] + static void abort_application (LogCategories category, std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (category, message.c_str (), log_location, sloc); + } + + [[noreturn]] + static void abort_application (LogCategories category, std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (category, message.data (), log_location, sloc); + } + + [[noreturn]] + static void abort_application (const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (LOG_DEFAULT, message, log_location, sloc); + } + + [[noreturn]] + static void abort_application (std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (LOG_DEFAULT, message.c_str (), log_location, sloc); + } + + [[noreturn]] + static void abort_application (std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept + { + abort_application (LOG_DEFAULT, message.data (), log_location, sloc); + } + }; + + template [[gnu::always_inline]] + static inline constexpr auto pointer_add (TPtr ptr, size_t offset) noexcept -> TRet + { + return reinterpret_cast(reinterpret_cast(ptr) + offset); + } + + [[gnu::always_inline]] + static inline constexpr auto optional_string (const char* s, const char *replacement = nullptr) noexcept -> const char* + { + if (s != nullptr) [[likely]] { + return s; + } + + return replacement == nullptr ? "" : replacement; + } +} diff --git a/src/native/mono/shared/log_types.hh b/src/native/mono/shared/log_types.hh index 53e7fbc97df..66b1cae5097 100644 --- a/src/native/mono/shared/log_types.hh +++ b/src/native/mono/shared/log_types.hh @@ -6,7 +6,7 @@ #include #include "java-interop-logger.h" -#include +#include "log_level.hh" // We redeclare macros here #if defined(log_debug) diff --git a/src/native/mono/shared/xxhash.hh b/src/native/mono/shared/xxhash.hh new file mode 100644 index 00000000000..32365aceab0 --- /dev/null +++ b/src/native/mono/shared/xxhash.hh @@ -0,0 +1,194 @@ +#pragma once + +#include + +#if INTPTR_MAX == INT64_MAX +#define XXH_NO_STREAM +#define XXH_INLINE_ALL +#define XXH_NAMESPACE xaInternal_ +#include +#include +#endif + +// +// Based on original code at https://github.com/ekpyron/xxhashct +// +// Original code license: +// + +/** +* MIT License +* +* Copyright (c) 2021 Zachary Arnaise +* +* 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 +#include + +namespace xamarin::android +{ + class xxhash32 final + { + static constexpr uint32_t PRIME1 = 0x9E3779B1U; + static constexpr uint32_t PRIME2 = 0x85EBCA77U; + static constexpr uint32_t PRIME3 = 0xC2B2AE3DU; + static constexpr uint32_t PRIME4 = 0x27D4EB2FU; + static constexpr uint32_t PRIME5 = 0x165667B1U; + + public: + // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily + // understood and to run compile-time algorithm correctness tests + template + [[gnu::always_inline]] + static constexpr auto hash (const char *input, size_t len) noexcept -> uint32_t + { + return finalize ( + (len >= 16 ? h16bytes (input, len) : Seed + PRIME5) + static_cast(len), + (input) + (len & ~0xFU), + len & 0xF + ); + } + + template + [[gnu::always_inline]] + static constexpr auto hash (const char (&input)[Size]) noexcept -> uint32_t + { + return hash (input, Size - 1); + } + + template + [[gnu::always_inline]] + static constexpr auto hash (std::string_view const& input) noexcept -> uint32_t + { + return hash (input.data (), input.length ()); + } + + private: + // 32-bit rotate left. + template [[gnu::always_inline]] + static constexpr auto rotl (uint32_t x) noexcept -> uint32_t + { + return ((x << Bits) | (x >> (32 - Bits))); + } + + // Normal stripe processing routine. + [[gnu::always_inline]] + static constexpr auto round (uint32_t acc, const uint32_t input) noexcept -> uint32_t + { + return rotl<13> (acc + (input * PRIME2)) * PRIME1; + } + + template [[gnu::always_inline]] + static constexpr auto avalanche_step (const uint32_t h) noexcept -> uint32_t + { + return (h ^ (h >> RShift)) * Prime; + } + + // Mixes all bits to finalize the hash. + [[gnu::always_inline]] + static constexpr auto avalanche (const uint32_t h) noexcept -> uint32_t + { + return + avalanche_step<16, 1> ( + avalanche_step<13, PRIME3> ( + avalanche_step <15, PRIME2> (h) + ) + ); + } + + // little-endian version: all our target platforms are little-endian + [[gnu::always_inline]] + static constexpr auto endian32 (const char *v) noexcept -> uint32_t + { + return + static_cast(static_cast(v[0])) | + (static_cast(static_cast(v[1])) << 8) | + (static_cast(static_cast(v[2])) << 16) | + (static_cast(static_cast(v[3])) << 24); + } + + [[gnu::always_inline]] + static constexpr auto fetch32 (const char *p, const uint32_t v) noexcept -> uint32_t + { + return round (v, endian32 (p)); + } + + // Processes the last 0-15 bytes of p. + [[gnu::always_inline]] + static constexpr auto finalize (const uint32_t h, const char *p, size_t len) noexcept -> uint32_t + { + return + (len >= 4) ? finalize (rotl<17> (h + (endian32 (p) * PRIME3)) * PRIME4, p + 4, len - 4) : + (len > 0) ? finalize (rotl<11> (h + (static_cast(*p) * PRIME5)) * PRIME1, p + 1, len - 1) : + avalanche (h); + } + + [[gnu::always_inline]] + static constexpr auto h16bytes (const char *p, size_t len, const uint32_t v1, const uint32_t v2, const uint32_t v3, const uint32_t v4) noexcept -> uint32_t + { + return + (len >= 16) ? h16bytes (p + 16, len - 16, fetch32 (p, v1), fetch32 (p+4, v2), fetch32 (p+8, v3), fetch32 (p+12, v4)) : + rotl<1> (v1) + rotl<7> (v2) + rotl<12> (v3) + rotl<18> (v4); + } + + // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily + // understood + template + [[gnu::always_inline]] + static constexpr auto h16bytes (const char *p, size_t len) noexcept -> uint32_t + { + return h16bytes(p, len, Seed + PRIME1 + PRIME2, Seed + PRIME2, Seed, Seed - PRIME1); + } + }; + +#if INTPTR_MAX == INT64_MAX + class xxhash64 final + { + public: + [[gnu::always_inline]] + static auto hash (const char *p, size_t len) noexcept -> XXH64_hash_t + { + return XXH3_64bits (static_cast(p), len); + } + + [[gnu::always_inline]] + static consteval auto hash (std::string_view const& input) noexcept -> XXH64_hash_t + { + return constexpr_xxh3::XXH3_64bits_const (input.data (), input.length ()); + } + + // The C XXH64_64bits function from xxhash.h is not `constexpr` or `consteval`, so we cannot call it here. + // At the same time, at build time performance is not that important, so we call the "unoptmized" `consteval` + // C++ implementation here + template [[gnu::always_inline]] + static consteval auto hash (const char (&input)[Size]) noexcept -> XXH64_hash_t + { + return constexpr_xxh3::XXH3_64bits_const (input); + } + }; + + using hash_t = XXH64_hash_t; + using xxhash = xxhash64; +#else + using hash_t = uint32_t; + using xxhash = xxhash32; +#endif +} diff --git a/src/native/native-clr.csproj b/src/native/native-clr.csproj new file mode 100644 index 00000000000..6d5d008723d --- /dev/null +++ b/src/native/native-clr.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0 + Debug + AnyCPU + Exe + false + + + + + + $(MicrosoftAndroidSdkOutDir)lib\clr + CoreCLR + + + + + + + + diff --git a/src/native/native-mono.csproj b/src/native/native-mono.csproj index f9f5aeb7f70..8b3b439e761 100644 --- a/src/native/native-mono.csproj +++ b/src/native/native-mono.csproj @@ -11,7 +11,8 @@ - $(MicrosoftAndroidSdkOutDir)lib\mono\ + $(MicrosoftAndroidSdkOutDir)lib\mono + Mono diff --git a/src/native/native.targets b/src/native/native.targets index 1a9ad1c94aa..f9109320ebf 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -2,12 +2,10 @@ - - - $(IntermediateOutputPath)\$(CMakeRuntimeFlavor)\ - - - + + $(IntermediateOutputPath)\$(CMakeRuntimeFlavor) + + @@ -30,21 +28,21 @@ - <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> - <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> + <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\java-interop\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\libstub\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\libunwind\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\lz4\CMakeLists.txt" /> - - <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> + + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> - <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> + <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> - + <_ConfigureRuntimesInputs Include="mono\monodroid\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\runtime-base\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\shared\CMakeLists.txt" /> @@ -52,25 +50,25 @@ <_ConfigureRuntimesInputs Include="mono\tracing\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\xamarin-app-debug-helper\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\xamarin-app-stub\CMakeLists.txt" /> - + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-asan-Debug\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-asan-Release\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-ubsan-Debug\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-ubsan-Release\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - + <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - - <_ConfigureRuntimesInputs Include="clr\host\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\runtime-base\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\shared\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\startup\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\xamarin-app-stub\CMakeLists.txt" /> - + + <_ConfigureRuntimesInputs Include="clr\host\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\runtime-base\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\shared\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\startup\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\xamarin-app-stub\CMakeLists.txt" /> + @@ -79,7 +77,7 @@ <_ArchiveDSOOutput Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-archive-dso-stub\CMakeCache.txt')" /> - <_ArchiveOutputDirToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub" /> + <_ArchiveOutputDirToCreate Include="$(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub" /> @@ -90,7 +88,7 @@ <_ConfigureArchiveDSOStubCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - -DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" + -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub @@ -113,7 +111,7 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_CmakeAndroidFlags>-DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" @@ -130,7 +128,7 @@ - + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) --preset asan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) @@ -163,14 +161,14 @@ - - <_RuntimeSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> - <_RuntimeSources Include="common\archive-dso-stub\*.cc" /> - <_RuntimeSources Include="common\libstub\*.cc;common\libstub\*.hh" /> + + <_RuntimeSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> + <_RuntimeSources Include="common\archive-dso-stub\*.cc" /> + <_RuntimeSources Include="common\libstub\*.cc;common\libstub\*.hh" /> <_RuntimeSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> - - - + + + <_RuntimeSources Include="mono\monodroid\*.cc;mono\monodroid\*.hh" /> <_RuntimeSources Include="mono\runtime-base\*.cc;mono\runtime-base\*.hh" /> <_RuntimeSources Include="mono\shared\*.cc;mono\shared\*.hh" /> @@ -179,39 +177,33 @@ <_RuntimeSources Include="mono\xamarin-debug-app-helper\*.cc;mono\xamarin-debug-app-helper\*.hh" /> - - <_RuntimeSources Include="clr\host\*.cc;clr\host\*.hh" /> - <_RuntimeSources Include="clr\include\**\*.hh" /> - <_RuntimeSources Include="clr\startup\*.cc;clr\startup\*.hh" /> - <_RuntimeSources Include="clr\xamarin-app-stub\*.cc;clr\xamarin-app-stub\*.hh" /> + + <_RuntimeSources Include="clr\host\*.cc;clr\host\*.hh" /> + <_RuntimeSources Include="clr\include\**\*.hh" /> + <_RuntimeSources Include="clr\startup\*.cc;clr\startup\*.hh" /> + <_RuntimeSources Include="clr\xamarin-app-stub\*.cc;clr\xamarin-app-stub\*.hh" /> <_RuntimeSources Include="clr\runtime-base\*.cc;clr\runtime-base\*.hh" /> <_RuntimeSources Include="clr\shared\*.cc;clr\shared\*.hh" /> - + - - <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> + + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(_RuntimeSources)" /> - <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> - - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app.so')" /> - - - + <_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')" /> - - - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.debug.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.release.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')" /> @@ -235,7 +227,7 @@ @@ -292,10 +284,7 @@ - <_RuntimePackFiles Include="$(OutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)\*" - AndroidRID="%(AndroidSupportedTargetJitAbi.AndroidRID)" - AndroidRuntime="$(CMakeRuntimeFlavor)" - RuntimePackName="$(_RuntimePackName)" /> + <_RuntimePackFiles Include="$(OutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)\*" AndroidRID="%(AndroidSupportedTargetJitAbi.AndroidRID)" AndroidRuntime="$(CMakeRuntimeFlavor)" /> From 8e62329f52e563eb3fe8e2bd1e69ba7180b8ab23 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 13 Jan 2025 22:38:53 +0100 Subject: [PATCH 054/143] Reorg continued --- Configuration.props | 4 ++-- src/native/CMakeLists.txt | 19 +++++++------------ src/native/CMakePresets.json.in | 1 - src/native/clr/host/CMakeLists.txt | 8 ++++---- src/native/clr/runtime-base/CMakeLists.txt | 6 +++--- src/native/clr/shared/CMakeLists.txt | 4 ++-- src/native/clr/startup/CMakeLists.txt | 4 ++-- .../clr/xamarin-app-stub/CMakeLists.txt | 4 ++-- src/native/cmake/ArchiveDSOStub.cmake | 2 +- src/native/common/libstub/CMakeLists.txt | 2 +- src/native/mono/monodroid/CMakeLists.txt | 2 +- src/native/mono/monolibmono-android.map.txt | 15 --------------- src/native/native-clr.csproj | 2 +- src/native/native-mono.csproj | 2 +- src/native/native.targets | 18 ++++++++++-------- 15 files changed, 37 insertions(+), 56 deletions(-) delete mode 100644 src/native/mono/monolibmono-android.map.txt diff --git a/Configuration.props b/Configuration.props index 07a4740807e..2a019e51b4f 100644 --- a/Configuration.props +++ b/Configuration.props @@ -56,14 +56,14 @@ Microsoft.Android.Sdk.Darwin - $(BuildOutputDirectory)lib\packs\ + $(BuildOutputDirectory)lib\packs\ False False <_XABinRelativeInstallPrefix>lib\xamarin.android $(MSBuildThisFileDirectory)bin\$(Configuration)\$(_XABinRelativeInstallPrefix)\ <_MonoAndroidNETOutputRoot>$(XAInstallPrefix)xbuild-frameworks\Microsoft.Android\ <_MonoAndroidNETDefaultOutDir>$(_MonoAndroidNETOutputRoot)$(AndroidApiLevel)\ - $(BuildOutputDirectory)lib\runtimes\ + $(BuildOutputDirectory)lib\runtimes\ $(MicrosoftAndroidPacksRootDir)Microsoft.Android.Ref.$(AndroidApiLevel)\$(AndroidPackVersion)\ref\$(DotNetTargetFramework)\ $(MicrosoftAndroidPacksRootDir)$(MicrosoftAndroidSdkPackName)\$(AndroidPackVersion)\ $(MicrosoftAndroidSdkPackDir)\tools\ diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index ddd4d72a19c..af3904431e3 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -220,23 +220,18 @@ set(JAVA_INTEROP_INCLUDE_DIR ${JAVA_INTEROP_SRC_PATH}) set(CONSTEXPR_XXH3_DIR "${EXTERNAL_DIR}/constexpr-xxh3") set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") -include_directories(common/include) - if(IS_CLR_RUNTIME) set(XA_RUNTIME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/clr/include) macro(xa_add_include_directories TARGET) - target_include_directories( - ${TARGET} - PRIVATE - ${XA_RUNTIME_INCLUDE_DIR} - ${EXTERNAL_DIR} - ${CONSTEXPR_XXH3_DIR} - ${RUNTIME_INCLUDE_DIR} - ) + target_include_directories( + ${TARGET} + PRIVATE + ${XA_RUNTIME_INCLUDE_DIR} + ${EXTERNAL_DIR} + ${CONSTEXPR_XXH3_DIR} + ) endmacro() -else() - include_directories(mono) endif() # diff --git a/src/native/CMakePresets.json.in b/src/native/CMakePresets.json.in index 33c910f6845..5544b1252b0 100644 --- a/src/native/CMakePresets.json.in +++ b/src/native/CMakePresets.json.in @@ -21,7 +21,6 @@ "ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES": "ON", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", "CMAKE_MAKE_PROGRAM": "@NinjaPath@", - "OUTPUT_PATH": "@OutputPath@", "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", "XA_BUILD_CONFIGURATION": "@XA_BUILD_CONFIGURATION@" } diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index b60cbc3b3ec..0d3beac163a 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -128,12 +128,12 @@ macro(lib_target_options TARGET_NAME) target_link_libraries( ${TARGET_NAME} ${LINK_LIBS} - xa::xamarin-app-clr + xa::xamarin-app ${SHARED_LIB_NAME} - xa::runtime-base-clr - xa::java-interop-clr + xa::runtime-base + xa::java-interop # xa::pinvoke-override-precompiled - xa::lz4-clr + xa::lz4 -llog ) endmacro () diff --git a/src/native/clr/runtime-base/CMakeLists.txt b/src/native/clr/runtime-base/CMakeLists.txt index 462a62e36dc..dbe6c2e634d 100644 --- a/src/native/clr/runtime-base/CMakeLists.txt +++ b/src/native/clr/runtime-base/CMakeLists.txt @@ -1,5 +1,5 @@ set(LIB_NAME runtime-base) -set(LIB_ALIAS xa::runtime-base-clr) +set(LIB_ALIAS xa::runtime-base) set(XA_RUNTIME_BASE_SOURCES android-system.cc @@ -43,8 +43,8 @@ target_include_directories( target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared-clr - xa::xamarin-app-clr + xa::shared + xa::xamarin-app ) xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native/clr/shared/CMakeLists.txt b/src/native/clr/shared/CMakeLists.txt index c1a85951663..aa6062066a6 100644 --- a/src/native/clr/shared/CMakeLists.txt +++ b/src/native/clr/shared/CMakeLists.txt @@ -1,5 +1,5 @@ set(LIB_NAME xa-shared-bits) -set(LIB_ALIAS xa::shared-clr) +set(LIB_ALIAS xa::shared) set(XA_SHARED_SOURCES helpers.cc @@ -27,7 +27,7 @@ macro(lib_target_options TARGET_NAME) target_link_libraries( ${TARGET_NAME} PUBLIC - xa::java-interop-clr + xa::java-interop -llog ) diff --git a/src/native/clr/startup/CMakeLists.txt b/src/native/clr/startup/CMakeLists.txt index 2f6951c6275..6ca5d69c590 100644 --- a/src/native/clr/startup/CMakeLists.txt +++ b/src/native/clr/startup/CMakeLists.txt @@ -1,5 +1,5 @@ set(LIB_NAME xamarin-startup) -set(LIB_ALIAS xa::xamarin-startup-clr) +set(LIB_ALIAS xa::xamarin-startup) set(XAMARIN_STARTUP_SOURCES zip.cc @@ -45,7 +45,7 @@ target_link_options( target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared-clr + xa::shared -llog ) diff --git a/src/native/clr/xamarin-app-stub/CMakeLists.txt b/src/native/clr/xamarin-app-stub/CMakeLists.txt index d23328f9ce7..c883ce2a2cb 100644 --- a/src/native/clr/xamarin-app-stub/CMakeLists.txt +++ b/src/native/clr/xamarin-app-stub/CMakeLists.txt @@ -1,5 +1,5 @@ -set(LIB_NAME xamarin-app-clr) -set(LIB_ALIAS xa::xamarin-app-clr) +set(LIB_NAME xamarin-app) +set(LIB_ALIAS xa::xamarin-app) set(XAMARIN_APP_SOURCES application_dso_stub.cc diff --git a/src/native/cmake/ArchiveDSOStub.cmake b/src/native/cmake/ArchiveDSOStub.cmake index f11b83372aa..8e4cdd2abac 100644 --- a/src/native/cmake/ArchiveDSOStub.cmake +++ b/src/native/cmake/ArchiveDSOStub.cmake @@ -1,3 +1,3 @@ set(ARCHIVE_DSO_STUB_LIB_NAME "archive-dso-stub") set(ARCHIVE_DSO_STUB_LIB_FILE_NAME "lib${ARCHIVE_DSO_STUB_LIB_NAME}.so") -set(XA_ARCHIVE_STUB_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/dsostubs/${ANDROID_RID}") +set(XA_ARCHIVE_STUB_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}") diff --git a/src/native/common/libstub/CMakeLists.txt b/src/native/common/libstub/CMakeLists.txt index 70563594fc4..28ec03682c0 100644 --- a/src/native/common/libstub/CMakeLists.txt +++ b/src/native/common/libstub/CMakeLists.txt @@ -1,4 +1,4 @@ -set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/libstubs/${ANDROID_RID}") +set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}") set(XAMARIN_STUB_LIB_SOURCES stub.cc diff --git a/src/native/mono/monodroid/CMakeLists.txt b/src/native/mono/monodroid/CMakeLists.txt index e8026d8306e..00c05f97d18 100644 --- a/src/native/mono/monodroid/CMakeLists.txt +++ b/src/native/mono/monodroid/CMakeLists.txt @@ -241,7 +241,7 @@ xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_LIB}) target_link_options(${XAMARIN_MONO_ANDROID_LIB} PRIVATE - -Wl,--version-script,${CMAKE_SOURCE_DIR}/libmono-android.map.txt + -Wl,--version-script,${CMAKE_SOURCE_DIR}/mono/libmono-android.map.txt -Wl,--no-undefined-version ) diff --git a/src/native/mono/monolibmono-android.map.txt b/src/native/mono/monolibmono-android.map.txt deleted file mode 100644 index 18bcab675ef..00000000000 --- a/src/native/mono/monolibmono-android.map.txt +++ /dev/null @@ -1,15 +0,0 @@ -LIBMONO_ANDROID { - global: - JNI_OnLoad; - Java_mono_android_Runtime_dumpTimingData; - Java_mono_android_Runtime_init; - Java_mono_android_Runtime_initInternal; - Java_mono_android_Runtime_notifyTimeZoneChanged; - Java_mono_android_Runtime_propagateUncaughtException; - Java_mono_android_Runtime_register; - _monodroid_freeifaddrs; - _monodroid_getifaddrs; - - local: - *; -}; diff --git a/src/native/native-clr.csproj b/src/native/native-clr.csproj index 6d5d008723d..8148b8bc396 100644 --- a/src/native/native-clr.csproj +++ b/src/native/native-clr.csproj @@ -11,7 +11,7 @@ - $(MicrosoftAndroidSdkOutDir)lib\clr + $(NativeRuntimeOutputRootDir)clr CoreCLR diff --git a/src/native/native-mono.csproj b/src/native/native-mono.csproj index 8b3b439e761..e15e9565a66 100644 --- a/src/native/native-mono.csproj +++ b/src/native/native-mono.csproj @@ -11,7 +11,7 @@ - $(MicrosoftAndroidSdkOutDir)lib\mono + $(NativeRuntimeOutputRootDir)mono Mono diff --git a/src/native/native.targets b/src/native/native.targets index f9109320ebf..a94129000c0 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -2,9 +2,11 @@ - - $(IntermediateOutputPath)\$(CMakeRuntimeFlavor) - + + + $(IntermediateOutputPath)\$(CMakeRuntimeFlavor)\ + + @@ -77,7 +79,7 @@ <_ArchiveDSOOutput Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-archive-dso-stub\CMakeCache.txt')" /> - <_ArchiveOutputDirToCreate Include="$(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub" /> + <_ArchiveOutputDirToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub" /> @@ -88,7 +90,7 @@ <_ConfigureArchiveDSOStubCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" + -DOUTPUT_PATH="$(OutputPath)" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub @@ -111,7 +113,7 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - <_CmakeAndroidFlags>-DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath)" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" @@ -202,7 +204,7 @@ <_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')" /> @@ -290,7 +292,7 @@ From b58563c2f83e3a82288d8937d3266760eacb8679 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 14 Jan 2025 11:59:45 +0100 Subject: [PATCH 055/143] Build appears to be working At least files end up where they should be :P --- .../Microsoft.Android.Runtime.proj | 25 +++++++++++++++---- .../installers/create-installers.targets | 12 --------- src/native/clr/host/CMakeLists.txt | 2 +- src/native/native.targets | 10 ++++++-- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index a8963b51859..10b8842c3bf 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -35,6 +35,7 @@ projects that use the Microsoft.Android framework in .NET 6+. <_RuntimeFlavorDirName Condition=" '$(AndroidRuntime)' == 'Mono' Or '$(AndroidRuntime)' == '' ">mono + <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Java.Interop.dll" /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Mono.Android.dll" /> @@ -48,11 +49,25 @@ projects that use the Microsoft.Android framework in .NET 6+. - <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.debug.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.debug.so" /> - <_AndroidRuntimePackAssets Condition=" Exists('$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-android.release.so') " Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libnet-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" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.debug.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.debug.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so" /> + + + + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.debug.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.release.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libxamarin-debug-app-helper.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libxamarin-native-tracing.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libunwind_xamarin.a" /> + + + + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so" /> + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so" /> diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index 8f5b8b1e9a8..b7979948098 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -179,18 +179,6 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)K4os.Compression.LZ4.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ELFSharp.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ManifestOverlays\Timing.xml" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libc.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libm.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-arm64\libarchive-dso-stub.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-arm\libarchive-dso-stub.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-x64\libarchive-dso-stub.so" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-x86\libarchive-dso-stub.so" /> <_MSBuildTargetsSrcFiles Include="$(MSBuildTargetsSrcDir)\Xamarin.Android.AvailableItems.targets" /> diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index 0d3beac163a..b8d10b38b52 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -144,7 +144,7 @@ xa_add_include_directories(${XAMARIN_NET_ANDROID_LIB}) target_link_options(${XAMARIN_NET_ANDROID_LIB} PRIVATE - -Wl,--version-script,${CMAKE_SOURCE_DIR}/libnet-android.map.txt + -Wl,--version-script,${CMAKE_SOURCE_DIR}/clr/libnet-android.map.txt -Wl,--no-undefined-version ) diff --git a/src/native/native.targets b/src/native/native.targets index a94129000c0..f3588fa66b8 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -196,13 +196,19 @@ <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(_RuntimeSources)" /> <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> + + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app.so')" /> <_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')" /> + + + + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.debug.so')" /> + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.release.so')" /> From 8cc8b4f903d807db6b280933f44768da50af3ebb Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 14 Jan 2025 17:25:26 +0100 Subject: [PATCH 056/143] Properly resolve library stubs from runtime packs --- .../targets/Microsoft.Android.Sdk.Aot.targets | 3 +- .../Tasks/CollectAssemblyFilesForArchive.cs | 15 +++-- .../Tasks/CollectNativeFilesForArchive.cs | 5 +- .../CollectRuntimeConfigFilesForArchive.cs | 5 +- .../Tasks/GetAotArguments.cs | 5 +- .../Tasks/LinkApplicationSharedLibraries.cs | 28 +++++---- .../Utilities/DSOWrapperGenerator.cs | 16 +++-- .../Utilities/MonoAndroidHelper.cs | 59 +++++++++++++++---- .../Xamarin.Android.Common.targets | 29 +++++++-- 9 files changed, 120 insertions(+), 45 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 1ae80b94409..5f5c148acb7 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -91,7 +91,8 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). EnableLLVM="$(EnableLLVM)" Profiles="@(AndroidAotProfile)" StripLibraries="$(_AndroidAotStripLibraries)" - ZipAlignmentPages="$(AndroidZipAlignment)"> + ZipAlignmentPages="$(AndroidZipAlignment)" + ResolvedRuntimePacks="@(ResolvedRuntimePack)"> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs index a9b50ac09ce..9de0d72827b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs @@ -22,7 +22,14 @@ public class CollectAssemblyFilesToCompress : AndroidTask [Required] public string AssemblyCompressionDirectory { get; set; } = ""; - public bool EmbedAssemblies { get; set; } + [Required] + public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + + [Required] + public string ApkOutputPath { get; set; } = ""; + + [Required] + public string AppSharedLibrariesDir { get; set; } = ""; [Required] public bool EnableCompression { get; set; } @@ -55,9 +62,9 @@ public override bool RunTask () ResolvedFrameworkAssembliesOutput = ResolvedFrameworkAssemblies; ResolvedUserAssembliesOutput = ResolvedUserAssemblies; - // We aren't going to compress any assemblies - if (IncludeDebugSymbols || !EnableCompression || !EmbedAssemblies) - return true; + DSOWrapperGenerator.Config dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); + bool compress = !IncludeDebugSymbols && EnableCompression; + IDictionary>? compressedAssembliesInfo = null; var assemblies_to_compress = new List (); var compressed_assemblies_info = GetCompressedAssemblyInfo (); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs index 78b64397882..420ad70c319 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectNativeFilesForArchive.cs @@ -53,6 +53,9 @@ public class CollectNativeFilesForArchive : AndroidTask [Required] public string AndroidBinUtilsDirectory { get; set; } = ""; + [Required] + public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + [Required] public string IntermediateOutputPath { get; set; } = ""; @@ -68,7 +71,7 @@ public class CollectNativeFilesForArchive : AndroidTask public override bool RunTask () { var apk = new PackageFileListBuilder (); - var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, IntermediateOutputPath); + var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); var outputFiles = new List { ApkOutputPath diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs index 1aa86a4c907..14a8c3a0946 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs @@ -19,6 +19,9 @@ public class CollectRuntimeConfigFilesForArchive : AndroidTask [Required] public string AndroidBinUtilsDirectory { get; set; } = ""; + [Required] + public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + [Required] public string IntermediateOutputPath { get; set; } = ""; @@ -33,7 +36,7 @@ public class CollectRuntimeConfigFilesForArchive : AndroidTask public override bool RunTask () { var files = new PackageFileListBuilder (); - var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, IntermediateOutputPath); + var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); // We will place rc.bin in the `lib` directory next to the blob, to make startup slightly faster, as we will find the config file right after we encounter // our assembly store. Not only that, but also we'll be able to skip scanning the `base.apk` archive when split configs are enabled (which they are in 99% diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs index 749c1df612f..2870939144a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs @@ -32,6 +32,9 @@ public abstract class GetAotArguments : AsyncTask [Required] public string TargetName { get; set; } = ""; + [Required] + public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + /// /// Will be blank in .NET 6+ /// @@ -295,7 +298,7 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP libs.Add (Path.Combine (androidLibPath, "libc.so")); libs.Add (Path.Combine (androidLibPath, "libm.so")); } else if (!UseAndroidNdk && EnableLLVM) { - string libstubsPath = MonoAndroidHelper.GetLibstubsArchDirectoryPath (AndroidBinUtilsDirectory, arch); + string libstubsPath = MonoAndroidHelper.GetLibstubsArchDirectoryPath (ResolvedRuntimePacks, arch); libs.Add (Path.Combine (libstubsPath, "libc.so")); libs.Add (Path.Combine (libstubsPath, "libm.so")); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 4d9aef3bcd4..830cc2dbb62 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -43,6 +43,9 @@ sealed class InputFiles [Required] public string AndroidBinUtilsDirectory { get; set; } + [Required] + public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + [Required] public bool TargetsCLR { get; set; } @@ -117,13 +120,11 @@ void RunLinker (Config config) IEnumerable GetLinkerConfigs () { - string runtimeNativeLibsDir = MonoAndroidHelper.GetNativeLibsRootDirectoryPath (AndroidBinUtilsDirectory); - string runtimeNativeLibStubsDir = MonoAndroidHelper.GetLibstubsRootDirectoryPath (AndroidBinUtilsDirectory); var abis = new Dictionary (StringComparer.Ordinal); ITaskItem[] dsos = ApplicationSharedLibraries; foreach (ITaskItem item in dsos) { string abi = item.GetMetadata ("abi"); - abis [abi] = GatherFilesForABI (item.ItemSpec, abi, ObjectFiles, runtimeNativeLibsDir, runtimeNativeLibStubsDir); + abis [abi] = GatherFilesForABI (item.ItemSpec, abi, ObjectFiles); } string soname = TargetsCLR ? "libxamarin-app-clr.so" : "libxamarin-app.so"; @@ -207,19 +208,22 @@ IEnumerable GetLinkerConfigs () } } - InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem[] objectFiles, string runtimeNativeLibsDir, string runtimeNativeLibStubsDir) + InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem[] objectFiles) { - List extraLibraries = null; + AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi); + var libDirs = new HashSet (StringComparer.OrdinalIgnoreCase) { + MonoAndroidHelper.GetNativeLibsRootDirectoryPath (ResolvedRuntimePacks, arch), + MonoAndroidHelper.GetLibstubsArchDirectoryPath (ResolvedRuntimePacks, arch), + }; + string RID = MonoAndroidHelper.AbiToRid (abi); AndroidTargetArch targetArch = MonoAndroidHelper.AbiToTargetArch (abi); - string libStubsPath = Path.Combine (runtimeNativeLibStubsDir, RID); - string runtimeLibsDir = Path.Combine (runtimeNativeLibsDir, RID); - extraLibraries = new List { - $"-L \"{runtimeLibsDir}\"", - $"-L \"{libStubsPath}\"", - "-lc", - }; + var extraLibraries = new List (); + foreach (string dir in libDirs) { + extraLibraries.Add ($"-L \"{dir}\""); + } + extraLibraries.Add ("-lc"); return new InputFiles { OutputSharedLibrary = runtimeSharedLibrary, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs index 15801bf3dd3..66304e3ebdc 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs @@ -53,24 +53,22 @@ public Config (Dictionary stubPaths, string androidBi // const ulong PayloadSectionAlignment = 0x4000; - public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDirectory, string baseOutputDirectory) + public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDirectory, ITaskItem[] runtimePacks, string baseOutputDirectory) { var stubPaths = new Dictionary (); - string archiveDSOStubsRootDir = MonoAndroidHelper.GetDSOStubsRootDirectoryPath (androidBinUtilsDirectory); - foreach (string dir in Directory.EnumerateDirectories (archiveDSOStubsRootDir, "android-*")) { - string rid = Path.GetFileName (dir); - AndroidTargetArch arch = MonoAndroidHelper.RidToArchMaybe (rid); - if (arch == AndroidTargetArch.None) { - log.LogDebugMessage ($"Unable to extract a supported RID name from directory path '{dir}'"); + foreach (ITaskItem maybePack in runtimePacks) { + if (!MonoAndroidHelper.IsAndroidRuntimePack (maybePack, out string? packRID) || String.IsNullOrEmpty (packRID)) { continue; } - string stubPath = Path.Combine (dir, "libarchive-dso-stub.so"); + string packDir = MonoAndroidHelper.GetAndroidRuntimePackDir (maybePack); + string stubPath = Path.Combine (packDir, "libarchive-dso-stub.so"); if (!File.Exists (stubPath)) { - throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubPath}' does not exist"); + throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubPath}' does not exist in runtime pack {packDir}"); } + AndroidTargetArch arch = MonoAndroidHelper.RidToArch (packRID); stubPaths.Add (arch, stubPath); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index f50e1444750..dd6508d0496 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -569,29 +569,66 @@ static string GetToolsRootDirectoryRelativePath (string androidBinUtilsDirectory return relPath; } - public static string GetLibstubsArchDirectoryPath (string androidBinUtilsDirectory, AndroidTargetArch arch) +#if MSBUILD + public static bool IsAndroidRuntimePack (ITaskItem maybePack, out string? packRID) { - return Path.Combine (GetLibstubsRootDirectoryPath (androidBinUtilsDirectory), ArchToRid (arch)); + string? framework = maybePack.GetMetadata ("FrameworkName"); + if (String.IsNullOrEmpty (framework) || String.Compare ("Microsoft.Android", framework, StringComparison.Ordinal) != 0) { + packRID = null; + return false; + } + + packRID = maybePack.GetMetadata ("RuntimeIdentifier"); + return !String.IsNullOrEmpty (packRID); } - public static string GetLibstubsRootDirectoryPath (string androidBinUtilsDirectory) + public static string GetAndroidRuntimePackDir (ITaskItem pack) { - string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory); - return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "libstubs")); + return pack.GetMetadata ("PackageDirectory"); } - public static string GetDSOStubsRootDirectoryPath (string androidBinUtilsDirectory) + public static string GetAndroidRuntimePackNativeDir (ITaskItem[] runtimePacks, AndroidTargetArch arch) { - string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory); - return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "dsostubs")); + string rid = ArchToRid (arch); + ITaskItem? androidRuntimePack = null; + + foreach (ITaskItem pack in runtimePacks) { + if (!IsAndroidRuntimePack (pack, out string? packRID) || String.Compare (rid, packRID, StringComparison.OrdinalIgnoreCase) != 0) { + continue; + } + + androidRuntimePack = pack; + break; + } + + if (androidRuntimePack == null) { + throw new InvalidOperationException ($"Internal error: Android runtime pack for architecture {arch} not found"); + } + + string? packageDir = GetAndroidRuntimePackDir (androidRuntimePack); + if (String.IsNullOrEmpty (packageDir)) { + throw new InvalidOperationException ($"Internal error: Android runtime pack for architecture {arch} is missing package directory metadata"); + } + + return Path.Combine (packageDir, "runtimes", rid, "native"); + } + + public static string GetLibstubsArchDirectoryPath (ITaskItem[] runtimePacks, AndroidTargetArch arch) + { + return GetAndroidRuntimePackNativeDir (runtimePacks, arch); } - public static string GetNativeLibsRootDirectoryPath (string androidBinUtilsDirectory) + public static string GetDSOStubsRootDirectoryPath (ITaskItem[] runtimePacks, AndroidTargetArch arch) { - string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory); - return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "lib")); + return GetAndroidRuntimePackNativeDir (runtimePacks, arch); } + public static string GetNativeLibsRootDirectoryPath (ITaskItem[] runtimePacks, AndroidTargetArch arch) + { + return GetAndroidRuntimePackNativeDir (runtimePacks, arch); + } +#endif // MSBUILD + public static string? GetAssemblyCulture (ITaskItem assembly) { // The best option diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 32e17a28607..b39ce2faa48 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2092,6 +2092,7 @@ because xbuild doesn't support framework reference assemblies. AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" ZipAlignmentPages="$(AndroidZipAlignment)" TargetsCLR="$(_AndroidUseCLR)" + ResolvedRuntimePacks="@(ResolvedRuntimePack)" /> @@ -2194,7 +2195,7 @@ because xbuild doesn't support framework reference assemblies. <_ApkOutputPath>$(_BaseZipIntermediate) - + - + - + Date: Tue, 14 Jan 2025 20:48:23 +0100 Subject: [PATCH 057/143] Fix java runtime jar inclusion --- .../Xamarin.Android.Common.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index b39ce2faa48..4c316c2837d 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1364,12 +1364,12 @@ because xbuild doesn't support framework reference assemblies. - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_net6.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_net6.dex - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_clr.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_clr.dex From ed7e277e616aa1e4df1734f4cc9a33ed9a41706d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 14 Jan 2025 21:36:36 +0100 Subject: [PATCH 058/143] Recreate @(ResolvedRuntimePack) item group --- ...oft.Android.Sdk.AssemblyResolution.targets | 5 ++ .../Tasks/RecreateResolvedRuntimePacks.cs | 69 +++++++++++++++++++ .../Tasks/ResolveSdksTask.cs | 1 + 3 files changed, 75 insertions(+) create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs 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 5ac211718c4..baae21a5be5 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 @@ -13,6 +13,7 @@ _ResolveAssemblies MSBuild target. + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs new file mode 100644 index 00000000000..229df612e00 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs @@ -0,0 +1,69 @@ +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System; + +namespace Xamarin.Android.Tasks; + +public class RecreateResolvedRuntimePacks : AndroidTask +{ + public override string TaskPrefix => "RRRP"; + + [Required] + public ITaskItem[] ResolvedNativeLibraries { get; set; } + + [Output] + public ITaskItem[] ResolvedRuntimePacks { get; set; } + + public override bool RunTask () + { + // We need to find `libc.so` that comes from one of our runtime packs + var libcPath = String.Format ("{0}native{0}libc.so", Path.DirectorySeparatorChar); + var runtimePacks = new Dictionary (StringComparer.OrdinalIgnoreCase); + foreach (ITaskItem library in ResolvedNativeLibraries) { + if (!library.ItemSpec.EndsWith (libcPath, StringComparison.OrdinalIgnoreCase)) { + continue; + } + + if (!GetMetadata (library, "RuntimeIdentifier", out string? rid) || runtimePacks.ContainsKey (rid)) { + continue; + } + + if (!GetMetadata (library, "NuGetPackageId", out string? nugetPackageId)) { + continue; + } + + if (!GetMetadata (library, "NuGetPackageVersion", out string? nugetPackageVersion)) { + continue; + } + + string tail = String.Format ("{0}runtimes{0}{1}{2}", Path.DirectorySeparatorChar, rid, libcPath); + int tailIndex = library.ItemSpec.IndexOf (tail); + if (tailIndex < 0) { + continue; + } + string packageDir = library.ItemSpec.Substring (0, tailIndex); + + var pack = new TaskItem (nugetPackageId); + pack.SetMetadata ("FrameworkName", "Microsoft.Android"); + pack.SetMetadata ("NuGetPackageId", nugetPackageId); + pack.SetMetadata ("NuGetPackageVersion", nugetPackageVersion); + pack.SetMetadata ("RuntimeIdentifier", rid); + pack.SetMetadata ("PackageDirectory", packageDir); + + runtimePacks.Add (rid, pack); + } + ResolvedRuntimePacks = runtimePacks.Values.ToArray (); + + return !Log.HasLoggedErrors; + + bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue) + { + metadataValue = item.GetMetadata (metadataName); + return !String.IsNullOrEmpty (metadataValue); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs index 499f79625f8..e2af82a63e2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs @@ -30,6 +30,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Android.Build.Tasks; From 8be8b210243258881127652ee10c569f0b4a5515 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 15 Jan 2025 13:35:41 +0100 Subject: [PATCH 059/143] Double-check if a nuget package is indeed our runtime pack --- Configuration.props | 4 +- ...oft.Android.Sdk.AssemblyResolution.targets | 8 ++-- .../Tasks/RecreateResolvedRuntimePacks.cs | 37 +++++++++++++++++++ .../Utilities/DSOWrapperGenerator.cs | 7 +++- .../Xamarin.Android.Common.targets | 10 +++-- 5 files changed, 54 insertions(+), 12 deletions(-) diff --git a/Configuration.props b/Configuration.props index 2a019e51b4f..07a4740807e 100644 --- a/Configuration.props +++ b/Configuration.props @@ -56,14 +56,14 @@ Microsoft.Android.Sdk.Darwin - $(BuildOutputDirectory)lib\packs\ + $(BuildOutputDirectory)lib\packs\ False False <_XABinRelativeInstallPrefix>lib\xamarin.android $(MSBuildThisFileDirectory)bin\$(Configuration)\$(_XABinRelativeInstallPrefix)\ <_MonoAndroidNETOutputRoot>$(XAInstallPrefix)xbuild-frameworks\Microsoft.Android\ <_MonoAndroidNETDefaultOutDir>$(_MonoAndroidNETOutputRoot)$(AndroidApiLevel)\ - $(BuildOutputDirectory)lib\runtimes\ + $(BuildOutputDirectory)lib\runtimes\ $(MicrosoftAndroidPacksRootDir)Microsoft.Android.Ref.$(AndroidApiLevel)\$(AndroidPackVersion)\ref\$(DotNetTargetFramework)\ $(MicrosoftAndroidPacksRootDir)$(MicrosoftAndroidSdkPackName)\$(AndroidPackVersion)\ $(MicrosoftAndroidSdkPackDir)\tools\ 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 baae21a5be5..30e589ddc42 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 @@ -236,10 +236,10 @@ _ResolveAssemblies MSBuild target. <_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" /> - <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' != 'True' " Include="libnet-android.debug" /> - <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' != 'True' " Include="libnet-android.release" /> - <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' == 'True' " Include="libmono-android.debug" /> - <_ExcludedNativeLibraries Condition=" '$(_AndroidUseCLR)' == 'True' " Include="libmono-android.release" /> + <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'Mono' Or '$(AndroidRuntime)' == '' " Include="libnet-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'Mono' Or '$(AndroidRuntime)' == '' " Include="libnet-android.release" /> + <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.release" /> "RRRP"; + static readonly string[] RuntimeLibraries = [ + "libmono-android.debug.so", + "libmono-android.release.so", + "libnet-android.debug.so", + "libnet-android.release.so", + ]; + [Required] public ITaskItem[] ResolvedNativeLibraries { get; set; } @@ -47,6 +54,30 @@ public override bool RunTask () } string packageDir = library.ItemSpec.Substring (0, tailIndex); + // Double-check that this is in fact our runtime pack. This is needed to avoid the (however improbable) + // situation where the application references a nuget which comes with `libc.so` and we mistakenly identify + // it to be our runtime pack. + + // Archive DSO stub must always exist + if (!PackNativeFileExists (packageDir, rid, DSOWrapperGenerator.StubFileName)) { + Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain '{DSOWrapperGenerator.StubFileName}'. Pack ignored."); + continue; + } + + // Either one of the runtime libraries must exist + bool runtimeLibraryFound = false; + foreach (string runtimeLibrary in RuntimeLibraries) { + if (PackNativeFileExists (packageDir, rid, runtimeLibrary)) { + runtimeLibraryFound = true; + continue; + } + Log.LogDebugMessage ($"Runtime library '{runtimeLibrary}' not found in pack '{packageDir}'"); + } + if (!runtimeLibraryFound) { + Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain any runtime shared libraries. Pack ignored."); + continue; + } + var pack = new TaskItem (nugetPackageId); pack.SetMetadata ("FrameworkName", "Microsoft.Android"); pack.SetMetadata ("NuGetPackageId", nugetPackageId); @@ -65,5 +96,11 @@ bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue metadataValue = item.GetMetadata (metadataName); return !String.IsNullOrEmpty (metadataValue); } + + bool PackNativeFileExists (string packageDir, string rid, string fileName) + { + string packFilePath = Path.Combine (packageDir, "runtimes", rid, "native", fileName); + return File.Exists (packFilePath); + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs index 66304e3ebdc..612c24b928a 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs @@ -34,6 +34,8 @@ class DSOWrapperGenerator { internal const string RegisteredConfigKey = ".:!DSOWrapperGeneratorConfig!:."; + public const string StubFileName = "libarchive-dso-stub.so"; + internal class Config { public Dictionary DSOStubPaths { get; } @@ -63,9 +65,10 @@ public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDir } string packDir = MonoAndroidHelper.GetAndroidRuntimePackDir (maybePack); - string stubPath = Path.Combine (packDir, "libarchive-dso-stub.so"); + string stubRelPath = Path.Combine ("runtimes", packRID, "native", StubFileName); + string stubPath = Path.Combine (packDir, stubRelPath); if (!File.Exists (stubPath)) { - throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubPath}' does not exist in runtime pack {packDir}"); + throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubRelPath}' does not exist in runtime pack at {packDir}"); } AndroidTargetArch arch = MonoAndroidHelper.RidToArch (packRID); diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 4c316c2837d..fbc1d36d082 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -305,6 +305,8 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' And '$(EmbedAssembliesIntoApk)' == 'False' ">True <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' ">False + <_AndroidUseCLR Condition=" '$(AndroidRuntime)' == 'CoreCLR' ">True + <_AndroidUseCLR Condition=" '$(AndroidRuntime)' != 'CoreCLR' ">False @@ -1364,12 +1366,12 @@ because xbuild doesn't support framework reference assemblies. - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_net6.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_net6.dex - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_clr.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_clr.dex @@ -2068,13 +2070,13 @@ because xbuild doesn't support framework reference assemblies. - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app.so"> %(_BuildTargetAbis.Identity) - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app-clr.so"> %(_BuildTargetAbis.Identity) From c68c2ea335ed56d8b0d6c3e1e0a6ffd5149b5305 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 15 Jan 2025 14:19:41 +0100 Subject: [PATCH 060/143] Don't package runtime stubs --- ...oft.Android.Sdk.AssemblyResolution.targets | 6 +++ .../Tasks/RecreateResolvedRuntimePacks.cs | 51 +++++++++++++++++++ 2 files changed, 57 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 30e589ddc42..08fd08314e8 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 @@ -251,7 +251,13 @@ _ResolveAssemblies MSBuild target. + + + + <_ResolvedNativeLibraries Remove="@(_IgnoreSharedLibraries)" /> + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs index 79a2622b492..6eab3a0e6d7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs @@ -19,18 +19,51 @@ public class RecreateResolvedRuntimePacks : AndroidTask "libnet-android.release.so", ]; + static readonly string[] LibraryNamesToIgnore = [ + "libarchive-dso-stub.so", + "libc.so", + "libdl.so", + "liblog.so", + "libm.so", + "libz.so", + ]; + [Required] public ITaskItem[] ResolvedNativeLibraries { get; set; } [Output] public ITaskItem[] ResolvedRuntimePacks { get; set; } + // Contains items for libraries which are to be removed from @(_ResolvedNativeLibraries), so that + // they aren't copied to the AAB/APK. There's a number of such libraries in our runtime packs, they + // are used only at build time and mustn't be included in the application archives. + [Output] + public ITaskItem[] SharedLibrariesToIgnore { get; set; } + public override bool RunTask () { + var ignoreLibNames = new List (); + foreach (string libName in LibraryNamesToIgnore) { + ignoreLibNames.Add (String.Format ("{0}native{0}{1}", Path.DirectorySeparatorChar, libName)); + } + // We need to find `libc.so` that comes from one of our runtime packs var libcPath = String.Format ("{0}native{0}libc.so", Path.DirectorySeparatorChar); var runtimePacks = new Dictionary (StringComparer.OrdinalIgnoreCase); + var maybeIgnoreLibs = new Dictionary (StringComparer.OrdinalIgnoreCase); + var runtimePackPaths = new List (); + foreach (ITaskItem library in ResolvedNativeLibraries) { + foreach (string libPathTail in ignoreLibNames) { + if (!library.ItemSpec.EndsWith (libPathTail, StringComparison.OrdinalIgnoreCase)) { + continue; + } + + string libraryRid = library.GetMetadata ("RuntimeIdentifier") ?? String.Empty; + maybeIgnoreLibs[$"{libraryRid}{libPathTail}"] = library; + break; + } + if (!library.ItemSpec.EndsWith (libcPath, StringComparison.OrdinalIgnoreCase)) { continue; } @@ -85,10 +118,28 @@ public override bool RunTask () pack.SetMetadata ("RuntimeIdentifier", rid); pack.SetMetadata ("PackageDirectory", packageDir); + runtimePackPaths.Add (packageDir); runtimePacks.Add (rid, pack); } ResolvedRuntimePacks = runtimePacks.Values.ToArray (); + var librariesToIgnore = new List (); + foreach (string path in runtimePackPaths) { + string runtimePackPath = path; + if (path[path.Length - 1] != Path.DirectorySeparatorChar) { + runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; + } + + Log.LogDebugMessage ($"Runtime pack path: {runtimePackPath}"); + foreach (ITaskItem library in maybeIgnoreLibs.Values) { + if (library.ItemSpec.StartsWith (runtimePackPath)) { + librariesToIgnore.Add (library); + Log.LogDebugMessage ($" ignore library: {library}"); + } + } + }; + SharedLibrariesToIgnore = librariesToIgnore.ToArray (); + return !Log.HasLoggedErrors; bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue) From 946febe8fc9bb09d1e60751613c229ddf1442668 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 15 Jan 2025 14:21:08 +0100 Subject: [PATCH 061/143] Not needed --- .../Tasks/RecreateResolvedRuntimePacks.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs index 6eab3a0e6d7..b5641d18f05 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs @@ -130,11 +130,9 @@ public override bool RunTask () runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; } - Log.LogDebugMessage ($"Runtime pack path: {runtimePackPath}"); foreach (ITaskItem library in maybeIgnoreLibs.Values) { if (library.ItemSpec.StartsWith (runtimePackPath)) { librariesToIgnore.Add (library); - Log.LogDebugMessage ($" ignore library: {library}"); } } }; From 07d211f6dcf3929684bbb735e1071e4435c41456 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Jan 2025 11:46:02 +0100 Subject: [PATCH 062/143] Update to match `main` --- .../java/mono/android/clr/MonoPackageManager.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java index 6ece4b145a0..8b41859fa97 100644 --- a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java @@ -26,9 +26,20 @@ public class MonoPackageManager { static android.content.Context Context; - public static void LoadApplication (Context context, ApplicationInfo runtimePackage, String[] apks) + public static void LoadApplication (Context context) { synchronized (lock) { + android.content.pm.ApplicationInfo runtimePackage = context.getApplicationInfo (); + String[] apks = null; + String[] splitApks = runtimePackage.splitSourceDirs; + if (splitApks != null && splitApks.length > 0) { + apks = new String[splitApks.length + 1]; + apks [0] = runtimePackage.sourceDir; + System.arraycopy (splitApks, 0, apks, 1, splitApks.length); + } else { + apks = new String[] { runtimePackage.sourceDir }; + } + if (context instanceof android.app.Application) { Context = context; } @@ -54,7 +65,7 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack } // - // Should the order change here, src/native-clr/include/constants.hh must be updated accordingly + // Should the order change here, src/native/clr/include/constants.hh must be updated accordingly // String[] appDirs = new String[] {filesDir, cacheDir, dataDir}; boolean haveSplitApks = runtimePackage.splitSourceDirs != null && runtimePackage.splitSourceDirs.length > 0; From 3d3fe807655d23bf61fdfc808cd6f08ff52942fb Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Jan 2025 13:01:53 +0100 Subject: [PATCH 063/143] Remove unnecessary sources --- src/native-clr/CMakeLists.txt | 517 --------------------- src/native-clr/CMakePresets.json.in | 323 ------------- src/native-clr/java-interop/CMakeLists.txt | 42 -- src/native-clr/lz4/CMakeLists.txt | 43 -- src/native-clr/native-clr.csproj | 22 - src/native-clr/native-clr.targets | 140 ------ 6 files changed, 1087 deletions(-) delete mode 100644 src/native-clr/CMakeLists.txt delete mode 100644 src/native-clr/CMakePresets.json.in delete mode 100644 src/native-clr/java-interop/CMakeLists.txt delete mode 100644 src/native-clr/lz4/CMakeLists.txt delete mode 100644 src/native-clr/native-clr.csproj delete mode 100644 src/native-clr/native-clr.targets diff --git a/src/native-clr/CMakeLists.txt b/src/native-clr/CMakeLists.txt deleted file mode 100644 index 3f2a4c627a0..00000000000 --- a/src/native-clr/CMakeLists.txt +++ /dev/null @@ -1,517 +0,0 @@ -cmake_minimum_required(VERSION 3.21) - -# -# Read product version -# -file(STRINGS "../../Directory.Build.props" XA_PRODUCT_VERSION_XML REGEX "^[ \t]*(.*)") -string(REGEX REPLACE "^[ \t]*(.*)" "\\1" XA_VERSION "${XA_PRODUCT_VERSION_XML}") - -project( - android-native-bits - VERSION ${XA_VERSION} - DESCRIPTION ".NET for Android native runtime" - HOMEPAGE_URL "https://github.com/dotnet/android" - LANGUAGES CXX C ASM -) - -# -# Sanity checks -# -macro(ensure_variable_set VARNAME) - if(NOT ${VARNAME}) - message(FATAL_ERROR "Variable ${VARNAME} not set. Please set it either on command line with -D${VARNAME}=value or in the presets file") - endif() -endmacro() - -ensure_variable_set(ANDROID_ABI) -ensure_variable_set(CMAKE_ANDROID_NDK) -ensure_variable_set(CMAKE_BUILD_TYPE) -ensure_variable_set(OUTPUT_PATH) -ensure_variable_set(XA_BUILD_CONFIGURATION) -ensure_variable_set(XA_LIB_TOP_DIR) - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}" CACHE PATH "" FORCE) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OUTPUT_PATH}/${ANDROID_RID}" CACHE PATH "" FORCE) - -set(CMAKE_CXX_STANDARD 23) -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") -#include("${CMAKE_SOURCE_DIR}/cmake/ArchiveDSOStub.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 AND ENABLE_CLANG_UBSAN) - message(FATAL_ERROR "Both ASAN and UBSAN builds cannot be enabled at the same time") -endif() - -if(ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) - if(BUILD_ARCHIVE_DSO_STUB) - message(FATAL_ERROR "ASAN/UBSAN builds aren't supported by the archive DSO target") - endif() - - 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(ENABLE_CLANG_ASAN) - set(STATIC_LIB_NAME_SUFFIX "-clr-asan") -elseif(ENABLE_CLANG_UBSAN) - set(STATIC_LIB_NAME_SUFFIX "-clr-ubsan") -else() - set(STATIC_LIB_NAME_SUFFIX "-clr") -endif() - -if(DEBUG_BUILD) - set(STATIC_LIB_NAME_SUFFIX "${STATIC_LIB_NAME_SUFFIX}-debug") -else() - set(STATIC_LIB_NAME_SUFFIX "${STATIC_LIB_NAME_SUFFIX}-release") -endif() - -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() - -# -# Needed modules -# -# include(CheckIncludeFile) -# include(CheckCXXSymbolExists) -include(CheckCXXCompilerFlag) -include(CheckCCompilerFlag) -include(CheckLinkerFlag) - -# -# General config -# -set(XA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Build${XA_BUILD_CONFIGURATION}") -include("${XA_BUILD_DIR}/xa_build_configuration.cmake") - -# -# Paths -# -if(ANDROID_ABI MATCHES "^arm64-v8a") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM64}") - set(TOOLCHAIN_TRIPLE "${NDK_ABI_arm64-v8a_TRIPLE}") -elseif(ANDROID_ABI MATCHES "^armeabi-v7a") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_ARM}") - set(TOOLCHAIN_TRIPLE "${NDK_ABI_armeabi-v7a_TRIPLE}") -elseif(ANDROID_ABI MATCHES "^x86_64") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86_64}") - set(TOOLCHAIN_TRIPLE "${NDK_ABI_x86_64_TRIPLE}") -elseif(ANDROID_ABI MATCHES "^x86") - set(NET_RUNTIME_DIR "${NETCORE_APP_RUNTIME_DIR_X86}") - set(TOOLCHAIN_TRIPLE "${NDK_ABI_x86_TRIPLE}") -else() - message(FATAL "${ANDROID_ABI} is not supported for .NET 6+ builds") -endif() - - -file(REAL_PATH "../../" REPO_ROOT_DIR) -set(EXTERNAL_DIR "${REPO_ROOT_DIR}/external") -set(JAVA_INTEROP_SRC_PATH "${EXTERNAL_DIR}/Java.Interop/src/java-interop") -#set(LIBUNWIND_SOURCE_DIR "${EXTERNAL_DIR}/libunwind") -#set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") - -# -# Include directories -# -set(SYSROOT_CXX_INCLUDE_DIR ${CMAKE_SYSROOT}/usr/include/c++/v1) -set(MONO_RUNTIME_INCLUDE_DIR ${NET_RUNTIME_DIR}/native/include/mono-2.0) -set(JAVA_INTEROP_INCLUDE_DIR ${JAVA_INTEROP_SRC_PATH}) -set(XA_RUNTIME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) -set(CONSTEXPR_XXH3_DIR ${EXTERNAL_DIR}/constexpr-xxh3) - -macro(xa_add_include_directories TARGET) - target_include_directories( - ${TARGET} - PRIVATE - ${XA_RUNTIME_INCLUDE_DIR} - ${EXTERNAL_DIR} - ${CONSTEXPR_XXH3_DIR} - ) -endmacro() - -# -# Compiler defines -# -macro(xa_add_compile_definitions TARGET) - target_compile_definitions( - ${TARGET} - PRIVATE - XA_VERSION="${XA_VERSION}" - _REENTRANT - PLATFORM_ANDROID - ) - - if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") - target_compile_definitions( - ${TARGET} - PRIVATE - ANDROID64 - ) - endif() -endmacro() - -if(NOT BUILD_ARCHIVE_DSO_STUB) - if(DEBUG_BUILD AND NOT DISABLE_DEBUG) - add_compile_definitions(DEBUG) - endif() - - if(NOT DEBUG_BUILD) - add_compile_definitions(RELEASE NDEBUG) - endif() -endif() - -# -# Compiler argument macros -# -macro(_compiler_has_arg _lang _arg) - string(REGEX REPLACE "-|,|=" "_" _arg_name ${_arg}) - string(TOUPPER "${_lang}" _lang_upper) - - cmake_language(CALL check_${_lang}_compiler_flag "${_arg}" HAS_${_arg_name}_${_lang_upper}) - if(HAS_${_arg_name}_${_lang_upper}) - set(COMPILER_ARG_FOUND True) - else() - set(COMPILER_ARG_FOUND False) - endif() -endmacro() - -macro(cxx_compiler_has_arg _arg) - _compiler_has_arg(cxx ${_arg}) -endmacro() - -macro(c_compiler_has_arg _arg) - _compiler_has_arg(c ${_arg}) -endmacro() - -macro(_linker_has_arg _lang _arg) - string(REGEX REPLACE "-|,|=" "_" _arg_name ${_arg}) - string(TOUPPER "${_lang}" _lang_upper) - - check_linker_flag(${_lang} "${_arg}" HAS_${_arg_name}_LINKER_${_lang_upper}) - if(HAS_${_arg_name}_LINKER_${_lang_upper}) - set(LINKER_ARG_FOUND True) - else() - set(LINKER_ARG_FOUND False) - endif() -endmacro() - -macro(cxx_linker_has_arg _arg) - _linker_has_arg(CXX ${_arg}) -endmacro() - -macro(c_linker_has_arg _arg) - _linker_has_arg(C ${_arg}) -endmacro() - -macro(xa_check_c_args VARNAME _CHECK_ARGS) - set(_CHECKED_ARGS "") - - foreach(arg ${_CHECK_ARGS}) - c_compiler_has_arg(${arg}) - if(COMPILER_ARG_FOUND) - list(APPEND _CHECKED_ARGS "${arg}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_ARGS}") -endmacro() - -macro(xa_check_cxx_args VARNAME _CHECK_ARGS) - set(_CHECKED_ARGS "") - - foreach(arg ${_CHECK_ARGS}) - cxx_compiler_has_arg(${arg}) - if(COMPILER_ARG_FOUND) - list(APPEND _CHECKED_ARGS "${arg}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_ARGS}") -endmacro() - -macro(xa_check_c_linker_args VARNAME _CHECK_ARGS) - set(_CHECKED_ARGS "") - - foreach(arg ${_CHECK_ARGS}) - c_linker_has_arg(${arg}) - if(LINKER_ARG_FOUND) - list(APPEND _CHECKED_ARGS "${arg}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_ARGS}") -endmacro() - -macro(xa_check_cxx_linker_args VARNAME _CHECK_ARGS) - set(_CHECKED_ARGS "") - - foreach(arg ${_CHECK_ARGS}) - cxx_linker_has_arg(${arg}) - if(LINKER_ARG_FOUND) - list(APPEND _CHECKED_ARGS "${arg}") - endif() - endforeach() - - set(${VARNAME} "${_CHECKED_ARGS}") -endmacro() - -set(CLANG_CHECK_SOURCES "") -macro(add_clang_check_sources SOURCES) - foreach(_source ${SOURCES}) - cmake_path(IS_RELATIVE _source _relative_path) - if(${_relative_path}) - list(APPEND _LOCAL_CLANG_CHECK_SOURCES_ ${CMAKE_CURRENT_SOURCE_DIR}/${_source}) - else() - list(APPEND _LOCAL_CLANG_CHECK_SOURCES_ ${_source}) - endif() - endforeach() - set(CLANG_CHECK_SOURCES "${_LOCAL_CLANG_CHECK_SOURCES_};${CLANG_CHECK_SOURCES}" PARENT_SCOPE) -endmacro() - -# -# Compiler args -# -set(CMAKE_CXX_VISIBILITY_PRESET "hidden") -set(CMAKE_C_VISIBILITY_PRESET "hidden") - -# -# Common flags are used when building all external -# and our own code -# -set(POTENTIAL_COMMON_COMPILER_ARGS - -fstack-protector-strong - -fstrict-return - -flto=thin - -fno-strict-aliasing - -fno-function-sections - -fno-data-sections - -funswitch-loops - -Wa,-noexecstack - -fPIC - -O2 -) - -if(NOT BUILD_ARCHIVE_DSO_STUB) - list(APPEND POTENTIAL_COMMON_COMPILER_ARGS - -g - ) -endif() - -set(POTENTIAL_COMMON_LINKER_ARGS - -fstack-protector-strong - -flto=thin - 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 - -Wno-vla-cxx-extension - -Wimplicit-fallthrough - -Wmisleading-indentation - -Wnull-dereference - -Wpointer-arith - -Wshadow - -Wsign-compare - -Wtrampolines - -Wuninitialized - -fstrict-flex-arrays=3 -) - -if (ENABLE_CLANG_ASAN OR ENABLE_CLANG_UBSAN) - list(APPEND POTENTIAL_XA_COMMON_COMPILER_ARGS - -fno-omit-frame-pointer - -fno-optimize-sibling-calls - ) -endif() - -set(POTENTIAL_XA_DSO_LINKER_ARGS - -fpic - -fstack-clash-protection -) - -unset(SANITIZER_FLAGS) -if (ENABLE_CLANG_ASAN) - set(SANITIZER_FLAGS -fsanitize=address) - set(CHECKED_BUILD_INFIX "-checked+asan") -elseif(ENABLE_CLANG_UBSAN) - set(SANITIZER_FLAGS -fsanitize=undefined) - set(CHECKED_BUILD_INFIX "-checked+ubsan") -endif() - -if(SANITIZER_FLAGS) - message(STATUS) - message(STATUS "Got sanitizer: ${SANITIZER_FLAGS}") - message(STATUS) - - list(APPEND POTENTIAL_XA_COMMON_COMPILER_ARGS ${SANITIZER_FLAGS}) - list(APPEND POTENTIAL_XA_COMMON_LINKER_ARGS ${SANITIZER_FLAGS}) - list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${SANITIZER_FLAGS}) -endif() - -message(STATUS) -message(STATUS "Checking support for common compiler and linker args") -message(STATUS) -xa_check_cxx_args(COMMON_CXX_ARGS "${POTENTIAL_COMMON_COMPILER_ARGS}") -xa_check_c_args(COMMON_C_ARGS "${POTENTIAL_COMMON_COMPILER_ARGS}") -xa_check_cxx_linker_args(COMMON_CXX_LINKER_ARGS "${POTENTIAL_COMMON_LINKER_ARGS}") -xa_check_c_linker_args(COMMON_C_LINKER_ARGS "${POTENTIAL_COMMON_LINKER_ARGS}") - -message(STATUS) -message(STATUS "Checking support for XA common compiler and linker args") -message(STATUS) -xa_check_cxx_args(XA_COMMON_CXX_ARGS "${POTENTIAL_XA_COMMON_COMPILER_ARGS}") -xa_check_c_args(XA_COMMON_C_ARGS "${POTENTIAL_XA_COMMON_COMPILER_ARGS}") -xa_check_cxx_linker_args(XA_COMMON_CXX_LINKER_ARGS "${POTENTIAL_XA_COMMON_LINKER_ARGS}") -xa_check_c_linker_args(XA_COMMON_C_LINKER_ARGS "${POTENTIAL_XA_COMMON_LINKER_ARGS}") -xa_check_c_linker_args(XA_C_DSO_LINKER_ARGS "${POTENTIAL_XA_DSO_LINKER_ARGS}") -xa_check_cxx_linker_args(XA_CXX_DSO_LINKER_ARGS "${POTENTIAL_XA_DSO_LINKER_ARGS}") - -if(NOT BUILD_ARCHIVE_DSO_STUB) - 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}>") -endif() - -# -# Helper macros -# -macro(set_static_library_suffix TARGET_NAME) - if(STATIC_LIB_NAME_SUFFIX) - set_target_properties( - ${TARGET_NAME} - PROPERTIES - SUFFIX "${STATIC_LIB_NAME_SUFFIX}.a" - ) - endif() -endmacro() - -if(BUILD_ARCHIVE_DSO_STUB) - add_subdirectory(archive-dso-stub) -else() -# 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) -# add_subdirectory(pinvoke-override) - add_subdirectory(startup) - add_subdirectory(host) - -# if(DEBUG_BUILD) -# add_subdirectory(xamarin-debug-app-helper) -# endif() - -# add_subdirectory(monodroid) - - add_custom_target(run_static_analysis - COMMAND ${ANDROID_TOOLCHAIN_ROOT}/bin/clang-check -analyze -p="${CMAKE_CURRENT_BINARY_DIR}" ${CLANG_CHECK_SOURCES} > ${CMAKE_SOURCE_DIR}/static-analysis.${ANDROID_ABI}.${CMAKE_BUILD_TYPE}.txt 2>&1 - COMMAND_EXPAND_LISTS - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - USES_TERMINAL - ) -endif() diff --git a/src/native-clr/CMakePresets.json.in b/src/native-clr/CMakePresets.json.in deleted file mode 100644 index 5544b1252b0..00000000000 --- a/src/native-clr/CMakePresets.json.in +++ /dev/null @@ -1,323 +0,0 @@ -{ - "version": 3, - "cmakeMinimumRequired": { - "major": 3, - "minor": 21, - "patch": 0 - }, - - "configurePresets": [ - { - "name": "common", - "hidden": true, - "generator": "Ninja", - "debug": { - "output": true - }, - "toolchainFile": "@AndroidNdkDirectory@/build/cmake/android.toolchain.cmake", - "cacheVariables": { - "ANDROID_NDK": "@AndroidNdkDirectory@", - "ANDROID_TOOLCHAIN": "clang", - "ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES": "ON", - "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", - "CMAKE_MAKE_PROGRAM": "@NinjaPath@", - "XA_LIB_TOP_DIR": "@MicrosoftAndroidSdkOutDir@", - "XA_BUILD_CONFIGURATION": "@XA_BUILD_CONFIGURATION@" - } - }, - - { - "name": "common-debug", - "hidden": true, - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" - } - }, - - { - "name": "common-release", - "hidden": true, - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release" - } - }, - - { - "name": "default-common", - "hidden": true, - "inherits": "common", - "cacheVariables": { - "ANDROID_STL": "c++_static", - "ANDROID_CPP_FEATURES": "no-rtti exceptions" - } - }, - - { - "name": "analyzers-common", - "hidden": true, - "inherits": "common", - "cacheVariables": { - "ANDROID_STL": "c++_static", - "ANDROID_CPP_FEATURES": "rtti exceptions" - } - }, - - { - "name": "default-debug", - "hidden": true, - "inherits": ["default-common", "common-debug"] - }, - - { - "name": "default-release", - "hidden": true, - "inherits": ["default-common", "common-release"] - }, - - { - "name": "analyzers-debug", - "hidden": true, - "inherits": ["analyzers-common", "common-debug"] - }, - - { - "name": "analyzers-release", - "hidden": true, - "inherits": ["analyzers-common", "common-release"] - }, - - { - "name": "common-armeabi-v7a", - "hidden": true, - "cacheVariables": { - "ANDROID_ABI": "armeabi-v7a", - "ANDROID_NATIVE_API_LEVEL": "@NDK_ARMEABI_V7_API_NET@", - "ANDROID_PLATFORM": "android-@NDK_ARMEABI_V7_API_NET@", - "ANDROID_RID": "android-arm" - } - }, - - { - "name": "common-arm64-v8a", - "hidden": true, - "cacheVariables": { - "ANDROID_ABI": "arm64-v8a", - "ANDROID_NATIVE_API_LEVEL": "@NDK_ARM64_V8A_API_NET@", - "ANDROID_PLATFORM": "android-@NDK_ARM64_V8A_API_NET@", - "ANDROID_RID": "android-arm64" - } - }, - - { - "name": "common-x86", - "hidden": true, - "cacheVariables": { - "ANDROID_ABI": "x86", - "ANDROID_NATIVE_API_LEVEL": "@NDK_X86_API_NET@", - "ANDROID_PLATFORM": "android-@NDK_X86_API_NET@", - "ANDROID_RID": "android-x86" - } - }, - - { - "name": "common-x86_64", - "hidden": true, - "cacheVariables": { - "ANDROID_ABI": "x86_64", - "ANDROID_NATIVE_API_LEVEL": "@NDK_X86_64_API_NET@", - "ANDROID_PLATFORM": "android-@NDK_X86_64_API_NET@", - "ANDROID_RID": "android-x64" - } - }, - - { - "name": "asan-common", - "hidden": true, - "cacheVariables": { - "ENABLE_CLANG_ASAN": "ON" - } - }, - - { - "name": "ubsan-common", - "hidden": true, - "cacheVariables": { - "ENABLE_CLANG_UBSAN": "ON" - } - }, - - { - "name": "default-debug-armeabi-v7a", - "inherits": ["default-common", "common-debug", "common-armeabi-v7a"] - }, - - { - "name": "default-release-armeabi-v7a", - "inherits": ["default-common", "common-release", "common-armeabi-v7a"] - }, - - { - "name": "analyzers-debug-armeabi-v7a", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-armeabi-v7a"] - }, - - { - "name": "analyzers-release-armeabi-v7a", - "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-armeabi-v7a"] - }, - - { - "name": "asan-release-armeabi-v7a", - "inherits": ["analyzers-release-armeabi-v7a", "asan-common"] - }, - - { - "name": "asan-debug-armeabi-v7a", - "inherits": ["analyzers-debug-armeabi-v7a", "asan-common"] - }, - - { - "name": "ubsan-release-armeabi-v7a", - "inherits": ["analyzers-release-armeabi-v7a", "ubsan-common"] - }, - - { - "name": "ubsan-debug-armeabi-v7a", - "inherits": ["analyzers-debug-armeabi-v7a", "ubsan-common"] - }, - - - - { - "name": "default-debug-arm64-v8a", - "inherits": ["default-common", "common-debug", "common-arm64-v8a"] - }, - - { - "name": "default-release-arm64-v8a", - "inherits": ["default-common", "common-release", "common-arm64-v8a"] - }, - - { - "name": "analyzers-debug-arm64-v8a", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-arm64-v8a"] - }, - - { - "name": "analyzers-release-arm64-v8a", - "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-arm64-v8a"] - }, - - { - "name": "asan-release-arm64-v8a", - "inherits": ["analyzers-release-arm64-v8a", "asan-common"] - }, - - { - "name": "asan-debug-arm64-v8a", - "inherits": ["analyzers-debug-arm64-v8a", "asan-common"] - }, - - { - "name": "ubsan-release-arm64-v8a", - "inherits": ["analyzers-release-arm64-v8a", "ubsan-common"] - }, - - { - "name": "ubsan-debug-arm64-v8a", - "inherits": ["analyzers-debug-arm64-v8a", "ubsan-common"] - }, - - - - { - "name": "default-debug-x86", - "inherits": ["default-common", "common-debug", "common-x86"] - }, - - { - "name": "default-release-x86", - "inherits": ["default-common", "common-release", "common-x86"] - }, - - { - "name": "analyzers-debug-x86", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-x86"] - }, - - { - "name": "analyzers-release-x86", - "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-x86"] - }, - - { - "name": "asan-release-x86", - "inherits": ["analyzers-release-x86", "asan-common"] - }, - - { - "name": "asan-debug-x86", - "inherits": ["analyzers-debug-x86", "asan-common"] - }, - - { - "name": "ubsan-release-x86", - "inherits": ["analyzers-release-x86", "ubsan-common"] - }, - - { - "name": "ubsan-debug-x86", - "inherits": ["analyzers-debug-x86", "ubsan-common"] - }, - - - - { - "name": "default-debug-x86_64", - "inherits": ["default-common", "common-debug", "common-x86_64"] - }, - - { - "name": "default-release-x86_64", - "inherits": ["default-common", "common-release", "common-x86_64"] - }, - - { - "name": "analyzers-debug-x86_64", - "hidden": true, - "inherits": ["analyzers-common", "common-debug", "common-x86_64"] - }, - - { - "name": "analyzers-release-x86_64", - "hidden": true, - "inherits": ["analyzers-common", "common-release", "common-x86_64"] - }, - - { - "name": "asan-release-x86_64", - "inherits": ["analyzers-release-x86_64", "asan-common"] - }, - - { - "name": "asan-debug-x86_64", - "inherits": ["analyzers-debug-x86_64", "asan-common"] - }, - - { - "name": "ubsan-release-x86_64", - "inherits": ["analyzers-release-x86_64", "ubsan-common"] - }, - - { - "name": "ubsan-debug-x86_64", - "inherits": ["analyzers-debug-x86_64", "ubsan-common"] - } - ] -} diff --git a/src/native-clr/java-interop/CMakeLists.txt b/src/native-clr/java-interop/CMakeLists.txt deleted file mode 100644 index 24a233e2b80..00000000000 --- a/src/native-clr/java-interop/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -set(LIB_NAME xa-java-interop) -set(LIB_ALIAS xa::java-interop-clr) - -set(JAVA_INTEROP_SOURCES - ${JAVA_INTEROP_SRC_PATH}/java-interop-dlfcn.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop-mono.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc - ${JAVA_INTEROP_SRC_PATH}/java-interop.cc -) -add_clang_check_sources("${JAVA_INTEROP_SOURCES}") - -add_library( - ${LIB_NAME} - STATIC - ${JAVA_INTEROP_SOURCES} -) - -add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) - -set_static_library_suffix(${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} -) - -xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native-clr/lz4/CMakeLists.txt b/src/native-clr/lz4/CMakeLists.txt deleted file mode 100644 index 140034771f1..00000000000 --- a/src/native-clr/lz4/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -set(LIB_NAME xa-lz4) -set(LIB_ALIAS xa::lz4-clr) - -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}) - -set_static_library_suffix(${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 - "$" -) - -if(DEBUG_BUILD) - set_target_properties( - ${LIB_NAME} - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - ) -endif() - -xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native-clr/native-clr.csproj b/src/native-clr/native-clr.csproj deleted file mode 100644 index 59d9457516f..00000000000 --- a/src/native-clr/native-clr.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - netstandard2.0 - Debug - AnyCPU - Exe - false - - - - - - $(MicrosoftAndroidSdkOutDir)lib\coreclr\ - - - - - - - - diff --git a/src/native-clr/native-clr.targets b/src/native-clr/native-clr.targets deleted file mode 100644 index b9d668a740e..00000000000 --- a/src/native-clr/native-clr.targets +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="host\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="runtime-base\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="shared\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="startup\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="xamarin-app-stub\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="java-interop\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="lz4\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> - <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Debug\CMakeCache.txt')" /> - <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Release\CMakeCache.txt')" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-clr-Debug" /> - <_OutputDirsToCreate Include="$(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-clr-Release" /> - - - - - - <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON - <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - - <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" - - - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - --preset default-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-clr-Debug - - - <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> - $(CmakePath) - --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) - $(IntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-clr-Release - - - - - - - - - - - - <_MonoDroidSources Include="include/**/*.hh" /> - <_MonoDroidSources Include="host/*.cc" /> - <_MonoDroidSources Include="runtime-base/*.cc" /> - <_MonoDroidSources Include="shared/*.cc" /> - <_MonoDroidSources Include="startup/*.cc" /> - <_MonoDroidSources Include="xamarin-app-stub/*.cc" /> - <_MonoDroidSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> - <_MonoDroidSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> - - - - - - <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Debug\CMakeCache.txt')" /> - <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(IntermediateOutputPath)\%(AndroidRID)-clr-Release\CMakeCache.txt')" /> - <_BuildAndroidRuntimesInputs Include="@(_MonoDroidSources)" /> - <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.debug.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.release.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app-clr.so')" /> - <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app-clr.so')" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_RuntimePackFiles Include="$(OutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)\*" AndroidRID="%(AndroidSupportedTargetJitAbi.AndroidRID)" AndroidRuntime="CoreCLR" /> - - - - - From 1b110156efd46c2a27f1b6b5b3a3bdb8262c6c22 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Jan 2025 13:22:50 +0100 Subject: [PATCH 064/143] Import changes from https://github.com/dotnet/android/pull/9686/ --- .../Microsoft.Android.Runtime.proj | 1 - ...oft.Android.Sdk.AssemblyResolution.targets | 8 +- .../targets/Microsoft.Android.Sdk.targets | 3 +- .../Tasks/GenerateJavaStubs.cs | 93 +++++++++++++++++-- .../Utilities/ManifestDocument.cs | 12 +-- .../Xamarin.Android.Common.targets | 13 ++- 6 files changed, 100 insertions(+), 30 deletions(-) diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 10b8842c3bf..073296fa678 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -35,7 +35,6 @@ projects that use the Microsoft.Android framework in .NET 6+. <_RuntimeFlavorDirName Condition=" '$(AndroidRuntime)' == 'Mono' Or '$(AndroidRuntime)' == '' ">mono - <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Java.Interop.dll" /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Mono.Android.dll" /> 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 08fd08314e8..2009cacc468 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 @@ -236,10 +236,10 @@ _ResolveAssemblies MSBuild target. <_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" /> - <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'Mono' Or '$(AndroidRuntime)' == '' " Include="libnet-android.debug" /> - <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'Mono' Or '$(AndroidRuntime)' == '' " Include="libnet-android.release" /> - <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.debug" /> - <_ExcludedNativeLibraries Condition=" '$(AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.release" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'Mono' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'Mono' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.release" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.release" /> - + Condition="Exists('$(MSBuildThisFileDirectory)..\tools\Xamarin.Android.Common.Debugging.props')"/> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 806bb19a3fd..89299d4bfec 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -72,11 +72,6 @@ public class GenerateJavaStubs : AndroidTask [Required] public string AndroidRuntime { get; set; } = ""; - public string CodeGenerationTarget { get; set; } = ""; - - AndroidRuntime androidRuntime; - JavaPeerStyle codeGenerationTarget; - internal const string AndroidSkipJavaStubGeneration = "AndroidSkipJavaStubGeneration"; public override bool RunTask () @@ -248,11 +243,91 @@ void Run (bool useMarshalMethods) internal static Dictionary MaybeGetArchAssemblies (Dictionary> dict, AndroidTargetArch arch) { - if (!dict.TryGetValue (arch, out Dictionary archDict)) { - return new Dictionary (StringComparer.OrdinalIgnoreCase); + if (!string.Equals (AndroidRuntime, "MonoVM", StringComparison.OrdinalIgnoreCase)) { + Log.LogDebugMessage ($"Skipping MonoRuntimeProvider generation for {AndroidRuntime}"); + return; + } + + // For NativeAOT, generate JavaInteropRuntime.java + if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) { + const string fileName = "JavaInteropRuntime.java"; + string template = GetResource (fileName); + var contents = template.Replace ("@MAIN_ASSEMBLY_NAME@", TargetName); + var path = Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", fileName); + Log.LogDebugMessage ($"Writing: {path}"); + Files.CopyIfStringChanged (contents, path); + } + + // Create additional application java sources. + StringWriter regCallsWriter = new StringWriter (); + regCallsWriter.WriteLine ("// Application and Instrumentation ACWs must be registered first."); + foreach (TypeDefinition type in codeGenState.JavaTypesForJCW) { + if (JavaNativeTypeManager.IsApplication (type, codeGenState.TypeCache) || JavaNativeTypeManager.IsInstrumentation (type, codeGenState.TypeCache)) { + if (codeGenState.Classifier != null && !codeGenState.Classifier.FoundDynamicallyRegisteredMethods (type)) { + continue; + } + + string javaKey = JavaNativeTypeManager.ToJniName (type, codeGenState.TypeCache).Replace ('/', '.'); + regCallsWriter.WriteLine ( + codeGenerationTarget == JavaPeerStyle.XAJavaInterop1 ? + "\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);" : + "\t\tnet.dot.jni.ManagedPeer.registerNativeMembers ({1}.class, {1}.__md_methods);", + type.GetAssemblyQualifiedName (codeGenState.TypeCache), + javaKey + ); + } + } + regCallsWriter.Close (); + + var real_app_dir = Path.Combine (OutputDirectory, "src", "net", "dot", "android"); + string applicationTemplateFile = "ApplicationRegistration.java"; + SaveResource ( + applicationTemplateFile, + applicationTemplateFile, + real_app_dir, + template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ()) + ); + } + + IList MergeManifest (NativeCodeGenState codeGenState, Dictionary userAssemblies) + { + var manifest = new ManifestDocument (ManifestTemplate) { + PackageName = PackageName, + VersionName = VersionName, + ApplicationLabel = ApplicationLabel ?? PackageName, + Placeholders = ManifestPlaceholders, + Resolver = codeGenState.Resolver, + SdkDir = AndroidSdkDir, + TargetSdkVersion = AndroidSdkPlatform, + MinSdkVersion = MonoAndroidHelper.ConvertSupportedOSPlatformVersionToApiLevel (SupportedOSPlatformVersion).ToString (), + Debug = Debug, + MultiDex = MultiDex, + NeedsInternet = NeedsInternet, + AndroidRuntime = AndroidRuntime, + }; + // Only set manifest.VersionCode if there is no existing value in AndroidManifest.xml. + if (manifest.HasVersionCode) { + Log.LogDebugMessage ($"Using existing versionCode in: {ManifestTemplate}"); + } else if (!string.IsNullOrEmpty (VersionCode)) { + manifest.VersionCode = VersionCode; + } + manifest.Assemblies.AddRange (userAssemblies.Values.Select (item => item.ItemSpec)); + + if (!String.IsNullOrWhiteSpace (CheckedBuild)) { + // We don't validate CheckedBuild value here, this will be done in BuildApk. We just know that if it's + // on then we need android:debuggable=true and android:extractNativeLibs=true + manifest.ForceDebuggable = true; + manifest.ForceExtractNativeLibs = true; + } + + IList additionalProviders = manifest.Merge (Log, codeGenState.TypeCache, codeGenState.AllJavaTypes, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); + + // Only write the new manifest if it actually changed + if (manifest.SaveIfChanged (Log, MergedAndroidManifestOutput)) { + Log.LogDebugMessage ($"Saving: {MergedAndroidManifestOutput}"); } - return archDict; + return additionalProviders; } (bool success, NativeCodeGenState? stubsState) GenerateJavaSourcesAndMaybeClassifyMarshalMethods (AndroidTargetArch arch, Dictionary assemblies, Dictionary userAssemblies, bool useMarshalMethods, bool generateJavaCode) @@ -262,7 +337,7 @@ internal static Dictionary MaybeGetArchAssemblies (Dictionary (List allJavaTypes, List javaTypesForJCW) = ScanForJavaTypes (resolver, tdCache, assemblies, userAssemblies, useMarshalMethods); var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache, useMarshalMethods); var jcwGenerator = new JCWGenerator (Log, jcwContext) { - CodeGenerationTarget = codeGenerationTarget, + CodeGenerationTarget = string.Equals (AndroidRuntime, "MonoVM", StringComparison.OrdinalIgnoreCase) ? JavaPeerStyle.XAJavaInterop1 : JavaPeerStyle.JavaInterop1 }; bool success; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index cb42ffafaac..48726a75685 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -94,7 +94,7 @@ internal class ManifestDocument public bool ForceDebuggable { get; set; } public string VersionName { get; set; } public IVersionResolver VersionResolver { get; set; } = new MonoAndroidHelperVersionResolver (); - public AndroidRuntime AndroidRuntime { get; set; } + public string AndroidRuntime { get; set; } = "MonoVM"; string versionCode; @@ -673,12 +673,10 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L IList AddMonoRuntimeProviders (XElement app) { - (string packageName, string className) = AndroidRuntime switch { - AndroidRuntime.MonoVM => ("mono", "MonoRuntimeProvider"), - AndroidRuntime.CoreCLR => ("mono", "MonoRuntimeProvider"), - AndroidRuntime.NativeAOT => ("net.dot.jni.nativeaot", "NativeAotRuntimeProvider"), - _ => throw new NotSupportedException ($"Internal error: unsupported runtime type: {AndroidRuntime}") - }; + if (!string.Equals (AndroidRuntime, "MonoVM", StringComparison.OrdinalIgnoreCase)) { + //TODO: implement provider logic for non-Mono runtimes + return []; + } app.Add (CreateMonoRuntimeProvider ($"{packageName}.{className}", null, --AppInitOrder)); diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index fbc1d36d082..ef9d344012e 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -305,8 +305,8 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' And '$(EmbedAssembliesIntoApk)' == 'False' ">True <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' ">False - <_AndroidUseCLR Condition=" '$(AndroidRuntime)' == 'CoreCLR' ">True - <_AndroidUseCLR Condition=" '$(AndroidRuntime)' != 'CoreCLR' ">False + <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' == 'CoreCLR' ">True + <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' != 'CoreCLR' ">False @@ -1366,12 +1366,12 @@ because xbuild doesn't support framework reference assemblies. - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_net6.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_net6.dex - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_clr.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_clr.dex @@ -1523,7 +1523,6 @@ because xbuild doesn't support framework reference assemblies. - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app.so"> %(_BuildTargetAbis.Identity) - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app-clr.so"> %(_BuildTargetAbis.Identity) From fc00b0359a40e7152aaebe72b4f3dce3049a12ba Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Jan 2025 13:42:51 +0100 Subject: [PATCH 065/143] Mono -> MonoVM --- ...oft.Android.Sdk.AssemblyResolution.targets | 4 +-- .../Xamarin.Android.Common.targets | 2 +- src/native/CMakeLists.txt | 2 +- src/native/native-mono.csproj | 2 +- src/native/native.targets | 26 +++++++++---------- 5 files changed, 18 insertions(+), 18 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 2009cacc468..895db3484fa 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 @@ -236,8 +236,8 @@ _ResolveAssemblies MSBuild target. <_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" /> - <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'Mono' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.debug" /> - <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'Mono' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.release" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'MonoVM' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.debug" /> + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'MonoVM' Or '$(_AndroidRuntime)' == '' " Include="libnet-android.release" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.debug" /> <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.release" /> diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index ef9d344012e..5a9facbdc03 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1366,7 +1366,7 @@ because xbuild doesn't support framework reference assemblies. - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_net6.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_net6.dex diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index af3904431e3..2c288171705 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -46,7 +46,7 @@ include("${CMAKE_ANDROID_NDK}/build/cmake/abis.cmake") include("${CMAKE_SOURCE_DIR}/cmake/ArchiveDSOStub.cmake") string(TOLOWER "${RUNTIME_FLAVOR}" RUNTIME_FLAVOR_LOWER) -if (RUNTIME_FLAVOR_LOWER STREQUAL mono) +if (RUNTIME_FLAVOR_LOWER STREQUAL monovm) set(IS_MONO_RUNTIME True) set(IS_CLR_RUNTIME False) set(SOURCES_PREFIX "mono") diff --git a/src/native/native-mono.csproj b/src/native/native-mono.csproj index e15e9565a66..518fd728712 100644 --- a/src/native/native-mono.csproj +++ b/src/native/native-mono.csproj @@ -12,7 +12,7 @@ $(NativeRuntimeOutputRootDir)mono - Mono + MonoVM diff --git a/src/native/native.targets b/src/native/native.targets index f3588fa66b8..496d82e45c5 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -7,7 +7,7 @@ $(IntermediateOutputPath)\$(CMakeRuntimeFlavor)\ - + @@ -36,7 +36,7 @@ <_ConfigureRuntimesInputs Include="common\libstub\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\libunwind\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\lz4\CMakeLists.txt" /> - + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> @@ -44,7 +44,7 @@ <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> - + <_ConfigureRuntimesInputs Include="mono\monodroid\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\runtime-base\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\shared\CMakeLists.txt" /> @@ -52,12 +52,12 @@ <_ConfigureRuntimesInputs Include="mono\tracing\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\xamarin-app-debug-helper\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="mono\xamarin-app-stub\CMakeLists.txt" /> - + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-asan-Debug\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-asan-Release\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-ubsan-Debug\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-ubsan-Release\CMakeCache.txt')" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - + <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> @@ -130,7 +130,7 @@ - + <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) --preset asan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) @@ -169,8 +169,8 @@ <_RuntimeSources Include="common\libstub\*.cc;common\libstub\*.hh" /> <_RuntimeSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> - - + + <_RuntimeSources Include="mono\monodroid\*.cc;mono\monodroid\*.hh" /> <_RuntimeSources Include="mono\runtime-base\*.cc;mono\runtime-base\*.hh" /> <_RuntimeSources Include="mono\shared\*.cc;mono\shared\*.hh" /> @@ -200,18 +200,18 @@ <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app.so')" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app.so')" /> - - + + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.debug.so')" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.release.so')" /> - + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.debug.so')" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libnet-android.release.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')" /> @@ -235,7 +235,7 @@ From 73a54377a699890f3ec57a8e1475357af8e4387c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Jan 2025 14:09:37 +0100 Subject: [PATCH 066/143] Fixes --- .../xaprepare/xaprepare/ConfigAndData/Configurables.cs | 1 - .../xaprepare/xaprepare/Steps/Step_GenerateFiles.cs | 7 ------- .../Microsoft.Android.Sdk.DefaultProperties.targets | 8 ++++---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 01aefb637e4..9c77341f969 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -176,7 +176,6 @@ public static partial class Paths 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"); - public static readonly string NativeCLRSourcesDir = Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "src", "native-clr"); // 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 e7a48b4e4c0..e0bccf3ed01 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -58,7 +58,6 @@ protected override async Task Execute (Context context) Get_Configuration_Generated_Props (context), Get_Cmake_XA_Build_Configuration (context), Get_Cmake_Presets (context), - Get_Cmake_Presets_CLR (context), }; } else { return new List { @@ -67,7 +66,6 @@ protected override async Task Execute (Context context) Get_Configuration_Generated_Props (context), Get_Cmake_XA_Build_Configuration (context), Get_Cmake_Presets (context), - Get_Cmake_Presets_CLR (context), Get_Ndk_projitems (context), Get_XABuildConfig_cs (context), Get_Omnisharp_Json (context), @@ -138,11 +136,6 @@ GeneratedFile Get_Cmake_Presets (Context context) return GetCmakePresetsCommon (context, Configurables.Paths.NativeSourcesDir); } - GeneratedFile Get_Cmake_Presets_CLR (Context context) - { - return GetCmakePresetsCommon (context, Configurables.Paths.NativeCLRSourcesDir); - } - GeneratedFile Get_Configuration_Generated_Props (Context context) { const string OutputFileName = "Configuration.Generated.props"; diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index de279984448..d4c77958476 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -24,10 +24,10 @@ See: https://github.com/dotnet/sdk/blob/955c0fc7b06e2fa34bacd076ed39f61e4fb61716/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L16 --> <_GetChildProjectCopyToPublishDirectoryItems>false - false - true - <_AndroidRuntime Condition=" '$(PublishAot)' == 'true' and '$(UseMonoRuntime)' != 'true' ">NativeAOT - <_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' != 'true' ">CoreCLR + false + true + <_AndroidRuntime Condition=" '$(PublishAot)' == 'true' and '$(EnableMonoRuntime)' != 'true' ">NativeAOT + <_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(EnableMonoRuntime)' != 'true' ">CoreCLR <_AndroidRuntime Condition=" '$(_AndroidRuntime)' == '' ">MonoVM true From f69d0066494aef21db3db1ef4e7dd4ebbfc56044 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Jan 2025 18:10:27 +0100 Subject: [PATCH 067/143] Fixes and workarounds to make CoreCLR build happen --- .../Microsoft.Android.Runtime.proj | 2 +- ...oft.Android.Sdk.AssemblyResolution.targets | 5 +++-- ...soft.Android.Sdk.DefaultProperties.targets | 8 ++++---- .../targets/Microsoft.Android.Sdk.targets | 9 +++++++++ .../Tasks/LinkApplicationSharedLibraries.cs | 2 +- .../Tasks/ProcessAssemblies.cs | 9 ++++++++- .../Tasks/RecreateResolvedRuntimePacks.cs | 19 +++++++++++++++++-- .../Utilities/MonoAndroidHelper.cs | 7 ++++++- src/native/native.targets | 7 +++++-- 9 files changed, 54 insertions(+), 14 deletions(-) diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 073296fa678..377ad4ebaa1 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -52,7 +52,7 @@ projects that use the Microsoft.Android framework in .NET 6+. <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so" /> - + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.debug.so" /> <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.release.so" /> <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libxamarin-debug-app-helper.so" /> 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 895db3484fa..7295d9410e6 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 @@ -50,7 +50,6 @@ _ResolveAssemblies MSBuild target. @@ -249,7 +248,9 @@ _ResolveAssemblies MSBuild target. - + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index d4c77958476..de279984448 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -24,10 +24,10 @@ See: https://github.com/dotnet/sdk/blob/955c0fc7b06e2fa34bacd076ed39f61e4fb61716/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L16 --> <_GetChildProjectCopyToPublishDirectoryItems>false - false - true - <_AndroidRuntime Condition=" '$(PublishAot)' == 'true' and '$(EnableMonoRuntime)' != 'true' ">NativeAOT - <_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(EnableMonoRuntime)' != 'true' ">CoreCLR + false + true + <_AndroidRuntime Condition=" '$(PublishAot)' == 'true' and '$(UseMonoRuntime)' != 'true' ">NativeAOT + <_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' != 'true' ">CoreCLR <_AndroidRuntime Condition=" '$(_AndroidRuntime)' == '' ">MonoVM true diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets index 149c3ae323b..6367e48ff34 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets @@ -20,6 +20,15 @@ Pack="false" PrivateAssets="All" /> + + + + %(RuntimePackRuntimeIdentifiers);android-arm64 + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 830cc2dbb62..3318f983a59 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -212,7 +212,7 @@ InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem { AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi); var libDirs = new HashSet (StringComparer.OrdinalIgnoreCase) { - MonoAndroidHelper.GetNativeLibsRootDirectoryPath (ResolvedRuntimePacks, arch), + MonoAndroidHelper.GetNativeLibsRootDirectoryPath (Log, ResolvedRuntimePacks, arch), MonoAndroidHelper.GetLibstubsArchDirectoryPath (ResolvedRuntimePacks, arch), }; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs index bce699d3883..f2a3a1ec11d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs @@ -110,6 +110,13 @@ void SetAssemblyAbiMetadata (string abi, ITaskItem assembly, ITaskItem? symbol) void SetAssemblyAbiMetadata (ITaskItem assembly, ITaskItem? symbol) { string rid = assembly.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (rid)) { + throw new InvalidOperationException ($"Assembly '{assembly}' item doesn't have the required RuntimeIdentifier metadata"); + } + + if (!MonoAndroidHelper.IsValidRID (rid)) { + throw new InvalidOperationException ($"Assembly '{assembly}' item targets unsupported RuntimeIdentifier '{rid}'"); + } SetAssemblyAbiMetadata (AndroidRidAbiHelper.RuntimeIdentifierToAbi (rid), assembly, symbol); } @@ -165,7 +172,7 @@ void SetDestinationSubDirectory (ITaskItem assembly, ITaskItem? symbol) { string? rid = assembly.GetMetadata ("RuntimeIdentifier"); if (String.IsNullOrEmpty (rid)) { - throw new InvalidOperationException ($"Assembly '{assembly}' item is missing required "); + throw new InvalidOperationException ($"Assembly '{assembly}' item is missing required RuntimeIdentifier data"); } string? abi = AndroidRidAbiHelper.RuntimeIdentifierToAbi (rid); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs index b5641d18f05..de93bc82fb3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs @@ -12,9 +12,12 @@ public class RecreateResolvedRuntimePacks : AndroidTask { public override string TaskPrefix => "RRRP"; - static readonly string[] RuntimeLibraries = [ + static readonly string[] RuntimeLibrariesMonoVM = [ "libmono-android.debug.so", "libmono-android.release.so", + ]; + + static readonly string[] RuntimeLibrariesCoreCLR = [ "libnet-android.debug.so", "libnet-android.release.so", ]; @@ -31,6 +34,9 @@ public class RecreateResolvedRuntimePacks : AndroidTask [Required] public ITaskItem[] ResolvedNativeLibraries { get; set; } + [Required] + public string AndroidRuntime { get; set; } + [Output] public ITaskItem[] ResolvedRuntimePacks { get; set; } @@ -47,6 +53,15 @@ public override bool RunTask () ignoreLibNames.Add (String.Format ("{0}native{0}{1}", Path.DirectorySeparatorChar, libName)); } + string[] runtimeLibraries; + if (String.Compare ("MonoVM", AndroidRuntime, StringComparison.OrdinalIgnoreCase) == 0) { + runtimeLibraries = RuntimeLibrariesMonoVM; + } else if (String.Compare ("CoreCLR", AndroidRuntime, StringComparison.OrdinalIgnoreCase) == 0) { + runtimeLibraries = RuntimeLibrariesCoreCLR; + } else { + throw new NotSupportedException ($"Internal error: unsupported runtime flavor '{AndroidRuntime}'"); + } + // We need to find `libc.so` that comes from one of our runtime packs var libcPath = String.Format ("{0}native{0}libc.so", Path.DirectorySeparatorChar); var runtimePacks = new Dictionary (StringComparer.OrdinalIgnoreCase); @@ -99,7 +114,7 @@ public override bool RunTask () // Either one of the runtime libraries must exist bool runtimeLibraryFound = false; - foreach (string runtimeLibrary in RuntimeLibraries) { + foreach (string runtimeLibrary in runtimeLibraries) { if (PackNativeFileExists (packageDir, rid, runtimeLibrary)) { runtimeLibraryFound = true; continue; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index dd6508d0496..02797f267fa 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -623,8 +623,13 @@ public static string GetDSOStubsRootDirectoryPath (ITaskItem[] runtimePacks, And return GetAndroidRuntimePackNativeDir (runtimePacks, arch); } - public static string GetNativeLibsRootDirectoryPath (ITaskItem[] runtimePacks, AndroidTargetArch arch) + public static string GetNativeLibsRootDirectoryPath (TaskLoggingHelper log, ITaskItem[] runtimePacks, AndroidTargetArch arch) { + log.LogWarning ("Potential runtime packs:"); + foreach (ITaskItem item in runtimePacks) { + log.LogWarning ($" {item}"); + } + return GetAndroidRuntimePackNativeDir (runtimePacks, arch); } #endif // MSBUILD diff --git a/src/native/native.targets b/src/native/native.targets index 496d82e45c5..60ac2a34967 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -292,13 +292,16 @@ - <_RuntimePackFiles Include="$(OutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)\*" AndroidRID="%(AndroidSupportedTargetJitAbi.AndroidRID)" AndroidRuntime="$(CMakeRuntimeFlavor)" /> + <_RuntimePackFiles Include="$(OutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)\*" + AndroidRID="%(AndroidSupportedTargetJitAbi.AndroidRID)" + AndroidRuntime="$(CMakeRuntimeFlavor)" + RuntimePackName="$(_RuntimePackName)" /> From 956e24f5ff9a474d37e8fbbd88f614e445577760 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 17 Jan 2025 12:18:11 +0100 Subject: [PATCH 068/143] Hack to be able to use CoreCLR runtime pack we created --- .../Tasks/RecreateResolvedRuntimePacks.cs | 114 ++++++++++++------ 1 file changed, 79 insertions(+), 35 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs index de93bc82fb3..c633e039e3f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs @@ -68,7 +68,69 @@ public override bool RunTask () var maybeIgnoreLibs = new Dictionary (StringComparer.OrdinalIgnoreCase); var runtimePackPaths = new List (); + // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK + HashSet? coreClrHackLibcItems = AndroidRuntime == "CoreCLR" ? new HashSet () : null; + if (coreClrHackLibcItems != null) { + LogHackWarning (); + } + // HACK END + foreach (ITaskItem library in ResolvedNativeLibraries) { + // HACK START: when CoreCLR runtime pack is properly resolved by the SDK, this method's body + // should be moved here and the method removed. + MaybeMakeRuntimePackItem (library, useCoreClrHack: true); + // HACK END + } + + // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK + if (coreClrHackLibcItems != null) { + LogHackWarning (); + foreach (ITaskItem item in coreClrHackLibcItems) { + string fakePath = item.ItemSpec.Replace ("Mono", "CoreCLR"); + if (fakePath.IndexOf ("CoreCLR") < 0) { + throw new InvalidOperationException ("CoreCLR runtime pack hack doesn't work"); + } + + var fakeLibcItem = new TaskItem (fakePath); + item.CopyMetadataTo (fakeLibcItem); + item.SetMetadata ("FakeCoreClrRuntimePack", "True"); + MaybeMakeRuntimePackItem (fakeLibcItem, useCoreClrHack: false); + } + } + // HACK END + ResolvedRuntimePacks = runtimePacks.Values.ToArray (); + + var librariesToIgnore = new List (); + foreach (string path in runtimePackPaths) { + string runtimePackPath = path; + if (path[path.Length - 1] != Path.DirectorySeparatorChar) { + runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; + } + + foreach (ITaskItem library in maybeIgnoreLibs.Values) { + if (library.ItemSpec.StartsWith (runtimePackPath)) { + librariesToIgnore.Add (library); + } + } + }; + SharedLibrariesToIgnore = librariesToIgnore.ToArray (); + + return !Log.HasLoggedErrors; + + bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue) + { + metadataValue = item.GetMetadata (metadataName); + return !String.IsNullOrEmpty (metadataValue); + } + + bool PackNativeFileExists (string packageDir, string rid, string fileName) + { + string packFilePath = Path.Combine (packageDir, "runtimes", rid, "native", fileName); + return File.Exists (packFilePath); + } + + void MaybeMakeRuntimePackItem (ITaskItem library, bool useCoreClrHack) + { foreach (string libPathTail in ignoreLibNames) { if (!library.ItemSpec.EndsWith (libPathTail, StringComparison.OrdinalIgnoreCase)) { continue; @@ -80,28 +142,35 @@ public override bool RunTask () } if (!library.ItemSpec.EndsWith (libcPath, StringComparison.OrdinalIgnoreCase)) { - continue; + return; } if (!GetMetadata (library, "RuntimeIdentifier", out string? rid) || runtimePacks.ContainsKey (rid)) { - continue; + return; } if (!GetMetadata (library, "NuGetPackageId", out string? nugetPackageId)) { - continue; + return; } if (!GetMetadata (library, "NuGetPackageVersion", out string? nugetPackageVersion)) { - continue; + return; } string tail = String.Format ("{0}runtimes{0}{1}{2}", Path.DirectorySeparatorChar, rid, libcPath); int tailIndex = library.ItemSpec.IndexOf (tail); if (tailIndex < 0) { - continue; + return; } string packageDir = library.ItemSpec.Substring (0, tailIndex); + // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK + if (useCoreClrHack && coreClrHackLibcItems != null) { + LogHackWarning (); + coreClrHackLibcItems.Add (library); + } + // HACK END + // Double-check that this is in fact our runtime pack. This is needed to avoid the (however improbable) // situation where the application references a nuget which comes with `libc.so` and we mistakenly identify // it to be our runtime pack. @@ -109,7 +178,7 @@ public override bool RunTask () // Archive DSO stub must always exist if (!PackNativeFileExists (packageDir, rid, DSOWrapperGenerator.StubFileName)) { Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain '{DSOWrapperGenerator.StubFileName}'. Pack ignored."); - continue; + return; } // Either one of the runtime libraries must exist @@ -122,8 +191,8 @@ public override bool RunTask () Log.LogDebugMessage ($"Runtime library '{runtimeLibrary}' not found in pack '{packageDir}'"); } if (!runtimeLibraryFound) { - Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain any runtime shared libraries. Pack ignored."); - continue; + Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain any {AndroidRuntime} runtime shared libraries. Pack ignored."); + return; } var pack = new TaskItem (nugetPackageId); @@ -136,35 +205,10 @@ public override bool RunTask () runtimePackPaths.Add (packageDir); runtimePacks.Add (rid, pack); } - ResolvedRuntimePacks = runtimePacks.Values.ToArray (); - - var librariesToIgnore = new List (); - foreach (string path in runtimePackPaths) { - string runtimePackPath = path; - if (path[path.Length - 1] != Path.DirectorySeparatorChar) { - runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; - } - - foreach (ITaskItem library in maybeIgnoreLibs.Values) { - if (library.ItemSpec.StartsWith (runtimePackPath)) { - librariesToIgnore.Add (library); - } - } - }; - SharedLibrariesToIgnore = librariesToIgnore.ToArray (); - - return !Log.HasLoggedErrors; - - bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue) - { - metadataValue = item.GetMetadata (metadataName); - return !String.IsNullOrEmpty (metadataValue); - } - bool PackNativeFileExists (string packageDir, string rid, string fileName) + void LogHackWarning () { - string packFilePath = Path.Combine (packageDir, "runtimes", rid, "native", fileName); - return File.Exists (packFilePath); + Log.LogWarning ("HACK! HACK! Using CoreCLR resolution hack. Remove once SDK is updated!"); } } } From a7f2f3acb58c8b537dc52bb649ff21f0a2fab121 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 17 Jan 2025 19:16:33 +0100 Subject: [PATCH 069/143] Fake CoreCLR runtime pack works. Next step: use correct CoreCLR instead of the linux-bionic one --- .../Tasks/ProcessAssemblies.cs | 2 +- .../Tasks/RecreateResolvedRuntimePacks.cs | 26 ++++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs index f2a3a1ec11d..6798ce47239 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs @@ -100,7 +100,7 @@ public override bool RunTask () void SetAssemblyAbiMetadata (string abi, ITaskItem assembly, ITaskItem? symbol) { if (String.IsNullOrEmpty (abi)) { - throw new ArgumentException ("must not be null or empty", nameof (abi)); + throw new ArgumentException ($"must not be null or empty for assembly item '{assembly}'", nameof (abi)); } assembly.SetMetadata ("Abi", abi); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs index c633e039e3f..a48f9617906 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs @@ -1,10 +1,11 @@ -using Microsoft.Android.Build.Tasks; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; +using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System; + +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; namespace Xamarin.Android.Tasks; @@ -65,7 +66,7 @@ public override bool RunTask () // We need to find `libc.so` that comes from one of our runtime packs var libcPath = String.Format ("{0}native{0}libc.so", Path.DirectorySeparatorChar); var runtimePacks = new Dictionary (StringComparer.OrdinalIgnoreCase); - var maybeIgnoreLibs = new Dictionary (StringComparer.OrdinalIgnoreCase); + var maybeIgnoreLibs = new List (); var runtimePackPaths = new List (); // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK @@ -93,7 +94,7 @@ public override bool RunTask () var fakeLibcItem = new TaskItem (fakePath); item.CopyMetadataTo (fakeLibcItem); - item.SetMetadata ("FakeCoreClrRuntimePack", "True"); + fakeLibcItem.SetMetadata ("NuGetPackageId", item.GetMetadata ("NuGetPackageId").Replace ("Mono", "CoreCLR")); MaybeMakeRuntimePackItem (fakeLibcItem, useCoreClrHack: false); } } @@ -107,7 +108,13 @@ public override bool RunTask () runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; } - foreach (ITaskItem library in maybeIgnoreLibs.Values) { + // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK + if (coreClrHackLibcItems != null) { + LogHackWarning (); + runtimePackPath = runtimePackPath.Replace ("CoreCLR", "Mono"); + } + // HACK END + foreach (ITaskItem library in maybeIgnoreLibs) { if (library.ItemSpec.StartsWith (runtimePackPath)) { librariesToIgnore.Add (library); } @@ -136,8 +143,7 @@ void MaybeMakeRuntimePackItem (ITaskItem library, bool useCoreClrHack) continue; } - string libraryRid = library.GetMetadata ("RuntimeIdentifier") ?? String.Empty; - maybeIgnoreLibs[$"{libraryRid}{libPathTail}"] = library; + maybeIgnoreLibs.Add (library); break; } @@ -208,7 +214,7 @@ void MaybeMakeRuntimePackItem (ITaskItem library, bool useCoreClrHack) void LogHackWarning () { - Log.LogWarning ("HACK! HACK! Using CoreCLR resolution hack. Remove once SDK is updated!"); + Log.LogWarning ("[RecreateResolvedRuntimePacks] HACK! HACK! Using CoreCLR resolution hack. Remove once SDK is updated!"); } } } From 8a2da86258b5fb7e2d83121b2bec757243207166 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 20 Jan 2025 22:18:54 +0100 Subject: [PATCH 070/143] Add support for local version of CoreCLR runtime pack --- ...oft.Android.Sdk.AssemblyResolution.targets | 15 ++ .../Tasks/MaybeUseLocalClr.cs | 172 ++++++++++++++++++ .../Tasks/ProcessAssemblies.cs | 3 + 3 files changed, 190 insertions(+) create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs 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 7295d9410e6..f3dab6875b2 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 @@ -14,6 +14,7 @@ _ResolveAssemblies MSBuild target. + + + + + + + + + + + + <_InnerIntermediateOutputPath Condition=" '$(RuntimeIdentifier)' == '' ">$(IntermediateOutputPath)%(_RIDs.Identity)\ diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs new file mode 100644 index 00000000000..b0a48fab053 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Android.Tools; + +namespace Xamarin.Android.Tasks; + +public class MaybeUseLocalCLR : AndroidTask +{ + // + // Lists of items below must together create a full CoreCLR + // runtime pack. All components must be listed. This is just + // a temporary measure until there exist CoreCLR packs. + // When we have the packs, we will simply make sure that all the + // required CoreCLR pack items found in ResolvedFilesToPublish are + // also in our local directory. + // + + // Full file names, no path. + static readonly string[] RequiredClrComponents = [ + "System.Private.CoreLib.dll", + "libSystem.Security.Cryptography.Native.Android.dex", + "libSystem.Security.Cryptography.Native.Android.jar", + ]; + + // Just stems, without extension. Extensions we'll check for are: + static readonly string[] RequiredClrLibraries = [ + "libSystem.IO.Compression.Native", + "libSystem.Globalization.Native", + "libSystem.IO.Ports.Native", + "libSystem.Native", + "libSystem.Security.Cryptography.Native.Android", + "libcoreclr", + ]; + + static readonly string[] ClrLibraryExtensions = [ + ".so", + ".so.dbg", + ".a", + ]; + + public override string TaskPrefix => "MULC"; + + public string LocalClrDirectory { get; set; } = String.Empty; + + [Required] + public ITaskItem[] ResolvedFilesToPublish { get; set; } + + [Required] + public string AndroidRuntime { get; set; } = String.Empty; + + [Output] + public ITaskItem[] SharedLibrariesToAdd { get; set; } + + [Output] + public ITaskItem[] SharedLibrariesToIgnore { get; set; } + + public override bool RunTask () + { + if (String.Compare ("CoreCLR", AndroidRuntime, StringComparison.OrdinalIgnoreCase) != 0) { + Log.LogDebugMessage ("Not considering custom CLR runtime since target runtime is not CoreCLR."); + return true; + } + + if (String.IsNullOrEmpty (LocalClrDirectory)) { + Log.LogDebugMessage ("Local CLR directory not specified, will not use custom CLR runtime."); + return true; + } + + if (!Directory.Exists (LocalClrDirectory)) { + Log.LogWarning ($"Local CLR directory not found: ${LocalClrDirectory}"); + return true; + } + + var itemsToRemove = new List (); + var supportedArchitectures = new HashSet (); + foreach (ITaskItem lib in ResolvedFilesToPublish) { + ProcessItem (lib, itemsToRemove, supportedArchitectures); + } + + var itemsToAdd = new List (); + foreach (string required in RequiredClrComponents) { + MakeLocalPackItem (required, itemsToAdd, supportedArchitectures); + } + + foreach (string required in RequiredClrLibraries) { + foreach (string ext in ClrLibraryExtensions) { + MakeLocalPackItem ($"{required}{ext}", itemsToAdd, supportedArchitectures); + } + } + + SharedLibrariesToAdd = itemsToAdd.ToArray (); + SharedLibrariesToIgnore = itemsToRemove.ToArray (); + return !Log.HasLoggedErrors; + } + + void MakeLocalPackItem (string required, List itemsToAdd, HashSet supportedArchitectures) + { + foreach (AndroidTargetArch arch in MonoAndroidHelper.SupportedTargetArchitectures) { + if (!supportedArchitectures.Contains (arch)) { + continue; + } + + string rid = MonoAndroidHelper.ArchToRid (arch); + string filePath = Path.Combine (LocalClrDirectory, "runtimes", rid, "native", required); + + if (!File.Exists (filePath)) { + Log.LogWarning ($"Local CoreCLR pack file '{filePath}' does not exist."); + continue; + } + + string fileName = Path.GetFileName (filePath); + var item = new TaskItem (filePath); + item.SetMetadata ("AssetType", "native"); + item.SetMetadata ("CopyLocal", "true"); + item.SetMetadata ("CopyToPublishDirectory", "PreserveNewest"); + item.SetMetadata ("DestinationSubPath", fileName); + item.SetMetadata ("DropFromSingleFile", "true"); + item.SetMetadata ("NuGetPackageId", $"Local.App.Runtime.CoreCLR.{rid}"); + item.SetMetadata ("NuGetPackageVersion", "0.0.0.0"); + item.SetMetadata ("RelativePath", fileName); + item.SetMetadata ("RuntimeIdentifier", rid); + + Log.LogDebugMessage ($"Creating local CoreCLR runtime package item: {item}"); + itemsToAdd.Add (item); + } + } + + void ProcessItem (ITaskItem item, List itemsToRemove, HashSet supportedArchitectures) + { + if (LinuxBionicHack (item, itemsToRemove) || CoreClrItem (item, itemsToRemove)) { + return; + } + + string? rid = item.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (rid)) { + return; + } + + supportedArchitectures.Add (MonoAndroidHelper.RidToArch (rid)); + } + + bool CoreClrItem (ITaskItem item, List itemsToRemove) + { + // TODO: implement once CoreCLR runtime packs are available + return false; + } + + bool LinuxBionicHack (ITaskItem item, List itemsToRemove) + { + string? nugetId = item.GetMetadata ("NuGetPackageId"); + + if (String.IsNullOrEmpty (nugetId)) { + return false; + } + + const string BionicNugetIdPrefix = "Microsoft.NETCore.App.Runtime.linux-bionic-"; + if (!nugetId.StartsWith (BionicNugetIdPrefix, StringComparison.OrdinalIgnoreCase)) { + return false; + } + + Log.LogWarning ($"[MaybeUseLocalClr] HACK! HACK! Ignoring linux-bionic item {item}. Remove once SDK is updated!"); + itemsToRemove.Add (item); + + return true; + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs index 6798ce47239..c6084037070 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs @@ -36,6 +36,9 @@ public class ProcessAssemblies : AndroidTask public ITaskItem [] InputJavaLibraries { get; set; } = Array.Empty (); + public string AndroidRuntime { get; set; } = String.Empty; + public string LocalClrDirectory { get; set; } = String.Empty; + [Output] public ITaskItem []? OutputAssemblies { get; set; } From 915c0db5dfbd33aebe2f30ec400f68f5b8637a08 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 21 Jan 2025 13:53:25 +0100 Subject: [PATCH 071/143] Support for CoreCLR in xaprepare --- Makefile | 5 ++++ .../scripts/xa_build_configuration.cmake.in | 5 ++++ .../xaprepare/Application/KnownProperties.cs | 1 + .../Application/Properties.Defaults.cs.in | 1 + .../xaprepare/ConfigAndData/Configurables.cs | 30 ++++++++++++++++++- .../xaprepare/Steps/Step_GenerateFiles.cs | 5 ++++ .../xaprepare/xaprepare/xaprepare.targets | 1 + 7 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 85a0a28b92a..12b7b25434b 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ PREPARE_SCENARIO = PREPARE_CI_PR ?= 0 PREPARE_CI ?= 0 PREPARE_AUTOPROVISION ?= 0 +LOCAL_CLR ?= _PREPARE_CI_MODE_PR_ARGS = --no-emoji --run-mode=CI _PREPARE_CI_MODE_ARGS = $(_PREPARE_CI_MODE_PR_ARGS) -a @@ -65,6 +66,10 @@ ifeq ($(XA_FORCE_COMPONENT_REFRESH),true) _PREPARE_ARGS += -refresh endif +ifneq ($(LOCAL_CLR),) +_PREPARE_ARGS += -p:_LocalClrDirectory="$(LOCAL_CLR)" +endif + _PREPARE_ARGS += $(PREPARE_ARGS) include build-tools/scripts/msbuild.mk diff --git a/build-tools/scripts/xa_build_configuration.cmake.in b/build-tools/scripts/xa_build_configuration.cmake.in index ad6da1b812a..8d350f17d27 100644 --- a/build-tools/scripts/xa_build_configuration.cmake.in +++ b/build-tools/scripts/xa_build_configuration.cmake.in @@ -2,3 +2,8 @@ set(NETCORE_APP_RUNTIME_DIR_ARM "@NETCORE_APP_RUNTIME_ANDROID_ARM@") set(NETCORE_APP_RUNTIME_DIR_ARM64 "@NETCORE_APP_RUNTIME_ANDROID_ARM64@") set(NETCORE_APP_RUNTIME_DIR_X86 "@NETCORE_APP_RUNTIME_ANDROID_X86@") set(NETCORE_APP_RUNTIME_DIR_X86_64 "@NETCORE_APP_RUNTIME_ANDROID_X86_64@") + +set(CORECLR_APP_RUNTIME_DIR_ARM "@CORECLR_APP_RUNTIME_ANDROID_ARM@") +set(CORECLR_APP_RUNTIME_DIR_ARM64 "@CORECLR_APP_RUNTIME_ANDROID_ARM64@") +set(CORECLR_APP_RUNTIME_DIR_X86 "@CORECLR_APP_RUNTIME_ANDROID_X86@") +set(CORECLR_APP_RUNTIME_DIR_X86_64 "@CORECLR_APP_RUNTIME_ANDROID_X86_64@") \ No newline at end of file diff --git a/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs b/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs index 2d9fd7efcfa..4970148f1b6 100644 --- a/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs +++ b/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs @@ -39,6 +39,7 @@ static class KnownProperties public const string JavaSdkDirectory = "JavaSdkDirectory"; public const string JdkIncludePath = "JdkIncludePath"; public const string LibZipSourceFullPath = "LibZipSourceFullPath"; + public const string LocalClrDirectory = "_LocalClrDirectory"; public const string ManagedRuntime = "ManagedRuntime"; public const string MicrosoftAndroidSdkOutDir = "MicrosoftAndroidSdkOutDir"; public const string MonoCecilVersion = "MonoCecilVersion"; diff --git a/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in b/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in index 6e59af3ab6e..12da7a9940e 100644 --- a/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in +++ b/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in @@ -43,6 +43,7 @@ namespace Xamarin.Android.Prepare properties.Add (KnownProperties.JavaSdkDirectory, StripQuotes (@"@JavaSdkDirectory@")); properties.Add (KnownProperties.JdkIncludePath, StripQuotes (@"@JdkIncludePath@")); properties.Add (KnownProperties.LibZipSourceFullPath, StripQuotes (@"@LibZipSourceFullPath@")); + properties.Add (KnownProperties.LocalClrDirectory, StripQuotes (@"@_LocalClrDirectory@")); properties.Add (KnownProperties.ManagedRuntime, StripQuotes (@"@ManagedRuntime@")); properties.Add (KnownProperties.MicrosoftAndroidSdkOutDir, StripQuotes (@"@MicrosoftAndroidSdkOutDir@")); properties.Add (KnownProperties.MonoCecilVersion, StripQuotes ("@MonoCecilVersion@")); diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 9c77341f969..34deedc61d5 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -191,12 +191,18 @@ public static partial class Paths public static string OpenJDKInstallDir => GetCachedPath (ref openJDKInstallDir, () => Path.Combine (ctx.Properties.GetRequiredValue (KnownProperties.AndroidToolchainDirectory), Defaults.JdkFolder)); public static string OpenJDKCacheDir => GetCachedPath (ref openJDKCacheDir, () => ctx.Properties.GetRequiredValue (KnownProperties.AndroidToolchainCacheDirectory)); - // .NET 6 + // .NET 6+ public static string NetcoreAppRuntimeAndroidARM => GetCachedPath (ref netcoreAppRuntimeAndroidARM, () => GetNetcoreAppRuntimePath (ctx, "arm")); public static string NetcoreAppRuntimeAndroidARM64 => GetCachedPath (ref netcoreAppRuntimeAndroidARM64, () => GetNetcoreAppRuntimePath (ctx, "arm64")); public static string NetcoreAppRuntimeAndroidX86 => GetCachedPath (ref netcoreAppRuntimeAndroidX86, () => GetNetcoreAppRuntimePath (ctx, "x86")); public static string NetcoreAppRuntimeAndroidX86_64 => GetCachedPath (ref netcoreAppRuntimeAndroidX86_64, () => GetNetcoreAppRuntimePath (ctx, "x64")); + // CoreCLR + public static string CoreClrAppRuntimeAndroidARM => GetCachedPath (ref coreclrAppRuntimeAndroidARM, () => GetCoreClrAppRuntimePath (ctx, "arm")); + public static string CoreClrAppRuntimeAndroidARM64 => GetCachedPath (ref coreclrAppRuntimeAndroidARM64, () => GetCoreClrAppRuntimePath (ctx, "arm64")); + public static string CoreClrAppRuntimeAndroidX86 => GetCachedPath (ref coreclrAppRuntimeAndroidX86, () => GetCoreClrAppRuntimePath (ctx, "x86")); + public static string CoreClrAppRuntimeAndroidX86_64 => GetCachedPath (ref coreclrAppRuntimeAndroidX86_64, () => GetCoreClrAppRuntimePath (ctx, "x64")); + public static string MicrosoftNETWorkloadMonoPackageDir => Path.Combine ( XAPackagesDir, $"microsoft.net.workload.mono.toolchain.{{0}}.manifest-{ctx.Properties.GetRequiredValue (KnownProperties.DotNetMonoManifestVersionBand)}", @@ -242,6 +248,24 @@ static string GetNetcoreAppRuntimePath (Context ctx, string androidTarget) ); } + static string GetCoreClrAppRuntimePath (Context ctx, string androidTarget) + { + string? localClrDir = ctx.Properties.GetValue (KnownProperties.LocalClrDirectory); + if (!String.IsNullOrEmpty (localClrDir)) { + return Path.Combine (localClrDir, "runtimes", $"android-{androidTarget}"); + } + + // TODO: The nuget id and the ref package version are guesses atm, since the CoreCLR packages don't exist yet + Log.Instance.Todo ("The nuget id and the ref package version are guesses atm, since the CoreCLR packages don't exist yet"); + return Path.Combine ( + XAPackagesDir, + $"microsoft.netcore.app.runtime.coreclr.android-{androidTarget}", + ctx.Properties.GetRequiredValue (KnownProperties.MicrosoftNETCoreAppRefPackageVersion), + "runtimes", + $"android-{androidTarget}" + ); + } + static string EnsureAndroidToolchainBinDirectories () { if (androidToolchainBinDirectory != null) @@ -278,6 +302,10 @@ static string GetCachedPath (ref string? variable, Func creator) static string? netcoreAppRuntimeAndroidARM64; static string? netcoreAppRuntimeAndroidX86; static string? netcoreAppRuntimeAndroidX86_64; + static string? coreclrAppRuntimeAndroidARM; + static string? coreclrAppRuntimeAndroidARM64; + static string? coreclrAppRuntimeAndroidX86; + static string? coreclrAppRuntimeAndroidX86_64; } } } diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs index e0bccf3ed01..65eddb2c042 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateFiles.cs @@ -98,6 +98,11 @@ GeneratedFile Get_Cmake_XA_Build_Configuration (Context context) { "@NETCORE_APP_RUNTIME_ANDROID_ARM64@", Utilities.EscapePathSeparators (Configurables.Paths.NetcoreAppRuntimeAndroidARM64) }, { "@NETCORE_APP_RUNTIME_ANDROID_X86@", Utilities.EscapePathSeparators (Configurables.Paths.NetcoreAppRuntimeAndroidX86) }, { "@NETCORE_APP_RUNTIME_ANDROID_X86_64@", Utilities.EscapePathSeparators (Configurables.Paths.NetcoreAppRuntimeAndroidX86_64) }, + + { "@CORECLR_APP_RUNTIME_ANDROID_ARM@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidARM) }, + { "@CORECLR_APP_RUNTIME_ANDROID_ARM64@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidARM64) }, + { "@CORECLR_APP_RUNTIME_ANDROID_X86@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidX86) }, + { "@CORECLR_APP_RUNTIME_ANDROID_X86_64@", Utilities.EscapePathSeparators (Configurables.Paths.CoreClrAppRuntimeAndroidX86_64) }, }; return new GeneratedPlaceholdersFile ( diff --git a/build-tools/xaprepare/xaprepare/xaprepare.targets b/build-tools/xaprepare/xaprepare/xaprepare.targets index 4c8e3be8906..b0f428d4c7b 100644 --- a/build-tools/xaprepare/xaprepare/xaprepare.targets +++ b/build-tools/xaprepare/xaprepare/xaprepare.targets @@ -76,6 +76,7 @@ + From d4012bcceb8cf60052343f55faa82c09cebc3959 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 21 Jan 2025 18:07:16 +0100 Subject: [PATCH 072/143] Limit CoreCLR builds to android-arm64 for now --- Configuration.props | 5 ++++ src/native/native-clr.csproj | 4 +++ src/native/native.targets | 58 ++++++++++++++++++------------------ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/Configuration.props b/Configuration.props index 07a4740807e..a42ba164177 100644 --- a/Configuration.props +++ b/Configuration.props @@ -220,4 +220,9 @@ + + + + <_LocalClrDirectory>$(AndroidToolchainDirectory)\clr + diff --git a/src/native/native-clr.csproj b/src/native/native-clr.csproj index 8148b8bc396..2bcc54f139a 100644 --- a/src/native/native-clr.csproj +++ b/src/native/native-clr.csproj @@ -6,6 +6,10 @@ AnyCPU Exe false + + + arm64 + arm64-v8a diff --git a/src/native/native.targets b/src/native/native.targets index 60ac2a34967..15b6afbfacd 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -3,9 +3,9 @@ - - $(IntermediateOutputPath)\$(CMakeRuntimeFlavor)\ - + + $(IntermediateOutputPath)\$(CMakeRuntimeFlavor)\ + - <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> - <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> + <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\java-interop\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\libstub\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\libunwind\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="common\lz4\CMakeLists.txt" /> - <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> + <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_ConfigureRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> - <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> + <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug" /> <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-Release" /> @@ -64,13 +64,13 @@ <_OutputDirsToCreate Include="$(FlavorIntermediateOutputPath)\%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release" Condition="'$(EnableNativeAnalyzers)' == 'true'" /> - - <_ConfigureRuntimesInputs Include="clr\host\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\runtime-base\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\shared\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\startup\CMakeLists.txt" /> - <_ConfigureRuntimesInputs Include="clr\xamarin-app-stub\CMakeLists.txt" /> - + + <_ConfigureRuntimesInputs Include="clr\host\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\runtime-base\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\shared\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\startup\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="clr\xamarin-app-stub\CMakeLists.txt" /> + @@ -163,12 +163,12 @@ - - <_RuntimeSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> - <_RuntimeSources Include="common\archive-dso-stub\*.cc" /> - <_RuntimeSources Include="common\libstub\*.cc;common\libstub\*.hh" /> + + <_RuntimeSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> + <_RuntimeSources Include="common\archive-dso-stub\*.cc" /> + <_RuntimeSources Include="common\libstub\*.cc;common\libstub\*.hh" /> <_RuntimeSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> - + <_RuntimeSources Include="mono\monodroid\*.cc;mono\monodroid\*.hh" /> @@ -179,27 +179,27 @@ <_RuntimeSources Include="mono\xamarin-debug-app-helper\*.cc;mono\xamarin-debug-app-helper\*.hh" /> - - <_RuntimeSources Include="clr\host\*.cc;clr\host\*.hh" /> - <_RuntimeSources Include="clr\include\**\*.hh" /> - <_RuntimeSources Include="clr\startup\*.cc;clr\startup\*.hh" /> - <_RuntimeSources Include="clr\xamarin-app-stub\*.cc;clr\xamarin-app-stub\*.hh" /> + + <_RuntimeSources Include="clr\host\*.cc;clr\host\*.hh" /> + <_RuntimeSources Include="clr\include\**\*.hh" /> + <_RuntimeSources Include="clr\startup\*.cc;clr\startup\*.hh" /> + <_RuntimeSources Include="clr\xamarin-app-stub\*.cc;clr\xamarin-app-stub\*.hh" /> <_RuntimeSources Include="clr\runtime-base\*.cc;clr\runtime-base\*.hh" /> <_RuntimeSources Include="clr\shared\*.cc;clr\shared\*.hh" /> - + - - <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> + + <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Debug\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(AndroidSupportedTargetJitAbi->'$(FlavorIntermediateOutputPath)\%(AndroidRID)-Release\CMakeCache.txt')" /> <_BuildAndroidRuntimesInputs Include="@(_RuntimeSources)" /> - <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> + <_BuildAndroidRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Debug\libxamarin-app.so')" /> <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\Release\libxamarin-app.so')" /> - + <_BuildAndroidRuntimesOutputs Include="@(AndroidSupportedTargetJitAbi->'$(OutputPath)\%(AndroidRID)\libmono-android.debug.so')" /> From ef8257d14fc93fd01415e88e2d62514ffde42444 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 21 Jan 2025 19:05:15 +0100 Subject: [PATCH 073/143] Build tweaks to make progress easier Some of those changes will stay, most will go. Makes it possible to move foreward for now without having CoreCLR packs for all the targets. Only arm64 supported atm --- Configuration.props | 2 +- .../create-packs/Microsoft.Android.Runtime.proj | 13 +++++++------ src/native/clr/host/CMakeLists.txt | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Configuration.props b/Configuration.props index a42ba164177..00a9f676305 100644 --- a/Configuration.props +++ b/Configuration.props @@ -223,6 +223,6 @@ - <_LocalClrDirectory>$(AndroidToolchainDirectory)\clr + <_LocalClrDirectory Condition=" Exists('$(AndroidToolchainDirectory)\clr') ">$(AndroidToolchainDirectory)\clr diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 377ad4ebaa1..ff2c1dabc3b 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -61,12 +61,13 @@ projects that use the Microsoft.Android framework in .NET 6+. - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so" /> - <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so" /> + + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so" /> + <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so" /> diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index b8d10b38b52..c2464183fbd 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -106,7 +106,8 @@ macro(lib_target_options TARGET_NAME) ${TARGET_NAME} SYSTEM PRIVATE ${SYSROOT_CXX_INCLUDE_DIR} - ${MONO_RUNTIME_INCLUDE_DIR} + ${RUNTIME_INCLUDE_DIR} + ${TEMP_MONO_RUNTIME_INCLUDE_DIR} ${NATIVE_TRACING_INCLUDE_DIRS} ${LIBUNWIND_INCLUDE_DIRS} ) From f9478ef7fe27e7a9157371d29c12632df9b61494 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 21 Jan 2025 22:39:28 +0100 Subject: [PATCH 074/143] A couple more hacks This time to include the actual CoreCLR Android runtime in the apk --- .../Microsoft.Android.Runtime.proj | 2 +- ...oft.Android.Sdk.AssemblyResolution.targets | 27 ++++--- ...HackInjectAndroidRuntimeSharedLibraries.cs | 71 +++++++++++++++++++ .../Tasks/MaybeUseLocalClr.cs | 6 +- .../Tasks/ProcessAssemblies.cs | 3 +- 5 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index ff2c1dabc3b..af99678ba05 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -52,7 +52,7 @@ projects that use the Microsoft.Android framework in .NET 6+. <_AndroidRuntimePackAssets Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libnet-android.release.so" /> - + <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.debug.so" /> <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libmono-android.release.so" /> <_AndroidRuntimePackAssets Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libxamarin-debug-app-helper.so" /> 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 f3dab6875b2..a02dfa44f9f 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 @@ -15,6 +15,7 @@ _ResolveAssemblies MSBuild target. + + + + + + + + + <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.release" /> - - - <_ResolvedNativeLibraries Remove="@(_IgnoreSharedLibraries)" /> - + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs new file mode 100644 index 00000000000..e6040ee8444 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.IO; + +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Android.Tools; + +namespace Xamarin.Android.Tasks; + +// +// HACK! HACK! To be removed when CoreCLR runtime packs work properly. +// +// Injects CoreCLR runtime pack shared libraries into the `ResolvedFileToPublish` +// item group. +// +public class CoreClrHackInjectAndroidRuntimeSharedLibraries : AndroidTask +{ + public override string TaskPrefix => "CCHIARSL"; + + [Required] + public ITaskItem[] ResolvedFilesToPublish { get; set; } + + [Required] + public string AndroidRuntime { get; set; } = String.Empty; + + [Output] + public ITaskItem[] SharedLibrariesToAdd { get; set; } = Array.Empty (); + + public override bool RunTask () + { + if (String.Compare (AndroidRuntime, "CoreCLR", StringComparison.OrdinalIgnoreCase) != 0) { + return true; + } + + var sharedLibsToAdd = new List (); + foreach (ITaskItem item in ResolvedFilesToPublish) { + string fileName = Path.GetFileName (item.ItemSpec); + string dirName = Path.GetDirectoryName (item.ItemSpec).Replace ("Mono", "CoreCLR"); + ITaskItem newItem; + if (String.Compare (fileName, "libmono-android.release.so", StringComparison.OrdinalIgnoreCase) == 0) { + newItem = MakeItem (Path.Combine (dirName, "libnet-android.release.so"), item); + } else if (String.Compare (fileName, "libmono-android.debug.so", StringComparison.OrdinalIgnoreCase) == 0) { + newItem = MakeItem (Path.Combine (dirName, "libnet-android.debug.so"), item); + } else { + continue; + } + + sharedLibsToAdd.Add (newItem); + } + + SharedLibrariesToAdd = sharedLibsToAdd.ToArray (); + return !Log.HasLoggedErrors; + } + + ITaskItem MakeItem (string identity, ITaskItem templateItem) + { + var item = new TaskItem (identity); + templateItem.CopyMetadataTo (item); + + string fileName = Path.GetFileName (identity); + item.SetMetadata ("DestinationSubPath", fileName); + item.SetMetadata ("RelativePath", fileName); + + // No need to null check the metadata value - if it isn't there, then something's broken and we + // will let it crash. + item.SetMetadata ("NuGetPackageId", item.GetMetadata ("NuGetPackageId").Replace ("Mono", "CoreCLR")); + return item; + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs index b0a48fab053..2937f2eda3c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; @@ -10,6 +9,11 @@ namespace Xamarin.Android.Tasks; +// +// Optionally replaces all the CoreCLR items with corresponding ones found in a local +// directory, instead of a nuget. This is used whenever a developer wants to quickly +// iterate over changes to CoreCLR without publishing packages. +// public class MaybeUseLocalCLR : AndroidTask { // diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs index c6084037070..884a94519e6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs @@ -103,7 +103,8 @@ public override bool RunTask () void SetAssemblyAbiMetadata (string abi, ITaskItem assembly, ITaskItem? symbol) { if (String.IsNullOrEmpty (abi)) { - throw new ArgumentException ($"must not be null or empty for assembly item '{assembly}'", nameof (abi)); + string rid = assembly.GetMetadata ("RuntimeIdentifier") ?? "unknown"; + throw new ArgumentException ($"must not be null or empty for assembly item '{assembly}' (RID '{rid}')", nameof (abi)); } assembly.SetMetadata ("Abi", abi); From 5851e453def0845be06bcab8b50e50b130f48dfd Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 22 Jan 2025 11:21:24 +0100 Subject: [PATCH 075/143] Fix JCW generation for CoreCLR --- src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs | 5 +++-- .../Utilities/ManifestDocument.cs | 2 +- .../Xamarin.Android.Common.targets | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 89299d4bfec..ce2c534c943 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -243,8 +243,9 @@ void Run (bool useMarshalMethods) internal static Dictionary MaybeGetArchAssemblies (Dictionary> dict, AndroidTargetArch arch) { - if (!string.Equals (AndroidRuntime, "MonoVM", StringComparison.OrdinalIgnoreCase)) { - Log.LogDebugMessage ($"Skipping MonoRuntimeProvider generation for {AndroidRuntime}"); + if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.MonoVM && + androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { + Log.LogDebugMessage ($"Skipping MonoRuntimeProvider generation for: {androidRuntime}"); return; } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index 48726a75685..283cad40670 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -673,7 +673,7 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L IList AddMonoRuntimeProviders (XElement app) { - if (!string.Equals (AndroidRuntime, "MonoVM", StringComparison.OrdinalIgnoreCase)) { + if (AndroidRuntime != AndroidRuntime.MonoVM && AndroidRuntime != AndroidRuntime.CoreCLR) { //TODO: implement provider logic for non-Mono runtimes return []; } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 5a9facbdc03..4d864624d23 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1395,7 +1395,7 @@ because xbuild doesn't support framework reference assemblies. DependsOnTargets="_CollectRuntimeJarFilenames;$(_BeforeAddStaticResources);_GetMonoPlatformJarPath"> From f93a1affc67bf40e2e2cbce393468c37bf4b7cc8 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 22 Jan 2025 18:32:56 +0100 Subject: [PATCH 076/143] A handful of fixlets --- .../Xamarin.Android.Common.targets | 8 +------- src/native/CMakeLists.txt | 5 +++-- src/native/clr/host/CMakeLists.txt | 2 +- src/native/clr/host/host.cc | 2 ++ src/native/clr/startup/CMakeLists.txt | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 4d864624d23..39a9ccc69c9 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2069,17 +2069,11 @@ because xbuild doesn't support framework reference assemblies. - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app.so"> %(_BuildTargetAbis.Identity) - - - <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app-clr.so"> - %(_BuildTargetAbis.Identity) - - + #include #include #include diff --git a/src/native/clr/startup/CMakeLists.txt b/src/native/clr/startup/CMakeLists.txt index 6ca5d69c590..48600e115e8 100644 --- a/src/native/clr/startup/CMakeLists.txt +++ b/src/native/clr/startup/CMakeLists.txt @@ -32,7 +32,7 @@ target_compile_options( target_link_directories( ${LIB_NAME} PRIVATE - ${NET_RUNTIME_DIR}/native-clr + ${NET_RUNTIME_DIR}/native ) target_link_options( From f0b4254dc622a450b25b6c475dd6de48b2dc1282 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 22 Jan 2025 19:29:55 +0100 Subject: [PATCH 077/143] Fix JCW again --- src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index ce2c534c943..87381c2254e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -338,7 +338,7 @@ IList MergeManifest (NativeCodeGenState codeGenState, Dictionary allJavaTypes, List javaTypesForJCW) = ScanForJavaTypes (resolver, tdCache, assemblies, userAssemblies, useMarshalMethods); var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache, useMarshalMethods); var jcwGenerator = new JCWGenerator (Log, jcwContext) { - CodeGenerationTarget = string.Equals (AndroidRuntime, "MonoVM", StringComparison.OrdinalIgnoreCase) ? JavaPeerStyle.XAJavaInterop1 : JavaPeerStyle.JavaInterop1 + CodeGenerationTarget = androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.NativeAOT ? JavaPeerStyle.XAJavaInterop1 : JavaPeerStyle.JavaInterop1 }; bool success; From ac65631d788d78621549f2dbd70e0c6fc7fbba5b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 22 Jan 2025 20:00:48 +0100 Subject: [PATCH 078/143] Revert "Fix JCW again", trying to figure out what's actually broken This reverts commit 4ff8fd0802641e5529f6e4ffbcf3a7437d034779. --- src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 87381c2254e..f61816ce6f8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -338,7 +338,7 @@ IList MergeManifest (NativeCodeGenState codeGenState, Dictionary allJavaTypes, List javaTypesForJCW) = ScanForJavaTypes (resolver, tdCache, assemblies, userAssemblies, useMarshalMethods); var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache, useMarshalMethods); var jcwGenerator = new JCWGenerator (Log, jcwContext) { - CodeGenerationTarget = androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.NativeAOT ? JavaPeerStyle.XAJavaInterop1 : JavaPeerStyle.JavaInterop1 + CodeGenerationTarget = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM ? JavaPeerStyle.XAJavaInterop1 : JavaPeerStyle.JavaInterop1 }; bool success; From 94ebcbbea71b82d3254fe55c3b4781bd9506a70a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 22 Jan 2025 20:14:53 +0100 Subject: [PATCH 079/143] Add some temporary logging --- .../java/mono/android/clr/MonoPackageManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java index 8b41859fa97..a589505aa6f 100644 --- a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java @@ -28,6 +28,7 @@ public class MonoPackageManager { public static void LoadApplication (Context context) { + Log.w ("XACLR", "MonoPackageManager.LoadApplication: start"); synchronized (lock) { android.content.pm.ApplicationInfo runtimePackage = context.getApplicationInfo (); String[] apks = null; @@ -44,6 +45,7 @@ public static void LoadApplication (Context context) Context = context; } if (!initialized) { + Log.w ("XACLR", "MonoPackageManager.LoadApplication: initializing"); android.content.IntentFilter timezoneChangedFilter = new android.content.IntentFilter ( android.content.Intent.ACTION_TIMEZONE_CHANGED ); @@ -70,8 +72,10 @@ public static void LoadApplication (Context context) String[] appDirs = new String[] {filesDir, cacheDir, dataDir}; boolean haveSplitApks = runtimePackage.splitSourceDirs != null && runtimePackage.splitSourceDirs.length > 0; + Log.w ("XACLR", "MonoPackageManager.LoadApplication: load monodroid"); System.loadLibrary("monodroid"); + Log.w ("XACLR", "MonoPackageManager.LoadApplication: call Runtime.initInternal"); Runtime.initInternal ( language, apks, @@ -84,8 +88,10 @@ public static void LoadApplication (Context context) haveSplitApks ); + Log.w ("XACLR", "MonoPackageManager.LoadApplication: call registerApplications"); mono.android.app.ApplicationRegistration.registerApplications (); + Log.w ("XACLR", "MonoPackageManager.LoadApplication: initialized"); initialized = true; } } From 6533e58a9aa87c432abaf63a5f3b810d10210eb7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 23 Jan 2025 21:22:37 +0100 Subject: [PATCH 080/143] Runtime config properties now stored in libxamarin-app.so CoreCLR will not use the assembly blob at all, instead the properties will be handed over to the runtime per request. --- .../Tasks/GeneratePackageManagerJava.cs | 5 +- .../Utilities/ApplicationConfigCLR.cs | 4 +- ...icationConfigNativeAssemblyGeneratorCLR.cs | 114 +++++++++++++++++- .../Xamarin.Android.Common.targets | 5 + src/native/clr/include/xamarin-app.hh | 18 ++- .../xamarin-app-stub/application_dso_stub.cc | 44 ++++++- 6 files changed, 180 insertions(+), 10 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 97fde5d1e3b..d3f039d6642 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -69,6 +69,7 @@ public class GeneratePackageManagerJava : AndroidTask public bool EnableMarshalMethods { get; set; } public string RuntimeConfigBinFilePath { get; set; } + public string ProjectRuntimeConfigFilePath { get; set; } = String.Empty; public string BoundExceptionType { get; set; } public string PackageNamingPolicy { get; set; } @@ -325,12 +326,12 @@ void AddEnvironment () LLVMIR.LlvmIrComposer appConfigAsmGen; if (TargetsCLR) { - appConfigAsmGen = new ApplicationConfigNativeAssemblyGeneratorCLR (environmentVariables, systemProperties, Log) { + Dictionary? runtimeProperties = RuntimePropertiesParser.ParseConfig (ProjectRuntimeConfigFilePath); + appConfigAsmGen = new ApplicationConfigNativeAssemblyGeneratorCLR (environmentVariables, systemProperties, runtimeProperties, Log) { UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, AndroidPackageName = AndroidPackageName, PackageNamingPolicy = pnp, JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, - HaveRuntimeConfigBlob = haveRuntimeConfigBlob, NumberOfAssembliesInApk = assemblyCount, BundledAssemblyNameWidth = assemblyNameWidth, NativeLibraries = uniqueNativeLibraries, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs index 0e5593bb363..249efc6c031 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs @@ -3,7 +3,7 @@ namespace Xamarin.Android.Tasks; // Declaration order of fields and their types must correspond *exactly* to that in -// src/native-clr/xamarin-app-stub/xamarin-app.hh ApplicationConfig structure +// src/native/clr/xamarin-app-stub/xamarin-app.hh ApplicationConfig structure // // Type mappings: // @@ -26,9 +26,9 @@ sealed class ApplicationConfigCLR { public bool uses_assembly_preload; public bool jni_add_native_method_registration_attribute_present; - public bool have_runtime_config_blob; public bool marshal_methods_enabled; public bool ignore_split_configs; + public uint number_of_runtime_properties; public uint package_naming_policy; public uint environment_variable_count; public uint system_property_count; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index 24ec67e9e73..7a6dc4b964e 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -29,6 +29,11 @@ public override string GetComment (object data, string fieldName) } } + // Disable "Field 'X' is never assigned to, and will always have its default value Y" + // Classes below are used in native code generation, thus all the fields must be present + // but they aren't always assigned values (which is fine). + #pragma warning disable CS0649 + // Order of fields and their type must correspond *exactly* (with exception of the // ignored managed members) to that in // src/monodroid/jni/xamarin-app.hh DSOCacheEntry structure @@ -89,7 +94,7 @@ sealed class AssemblyStoreSingleAssemblyRuntimeData } // Order of fields and their type must correspond *exactly* to that in - // src/monodroid/jni/xamarin-app.hh AssemblyStoreRuntimeData structure + // src/native/clr/include/xamarin-app.hh AssemblyStoreRuntimeData structure sealed class AssemblyStoreRuntimeData { [NativePointer (IsNull = true)] @@ -101,6 +106,27 @@ sealed class AssemblyStoreRuntimeData public AssemblyStoreAssemblyDescriptor assemblies; } + // Order of fields and their types must correspond *exactly* to that in + // src/native/clr/include/xamarin-app.hh RuntimeProperty structure + sealed class RuntimeProperty + { + public string key; + public string value; + public uint value_size; + } + + // Order of fields and their types must correspond *exactly* to that in + // src/native/clr/include/xamarin-app.hh RuntimePropertyIndexEntry structure + sealed class RuntimePropertyIndexEntry + { + [NativeAssembler (Ignore = true)] + public string HashedKey; + + [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public ulong key_hash; + public uint index; + } + sealed class XamarinAndroidBundledAssemblyContextDataProvider : NativeAssemblerStructContextDataProvider { public override ulong GetBufferSize (object data, string fieldName) @@ -137,16 +163,20 @@ sealed class XamarinAndroidBundledAssembly [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToPreAllocatedBuffer = true)] public string name; } +#pragma warning restore CS0649 // Keep in sync with FORMAT_TAG in src/monodroid/jni/xamarin-app.hh const ulong FORMAT_TAG = 0x00025E6972616D58; // 'Xmari^XY' where XY is the format version SortedDictionary ? environmentVariables; SortedDictionary ? systemProperties; + SortedDictionary ? runtimeProperties; StructureInstance? application_config; List>? dsoCache; List>? aotDsoCache; List>? xamarinAndroidBundledAssemblies; + List>? runtimePropertiesData; + List>? runtimePropertyIndex; StructureInfo? applicationConfigStructureInfo; StructureInfo? dsoCacheEntryStructureInfo; @@ -154,11 +184,12 @@ sealed class XamarinAndroidBundledAssembly StructureInfo? xamarinAndroidBundledAssemblyStructureInfo; StructureInfo? assemblyStoreSingleAssemblyRuntimeDataStructureinfo; StructureInfo? assemblyStoreRuntimeDataStructureInfo; + StructureInfo? runtimePropertyStructureInfo; + StructureInfo? runtimePropertyIndexEntryStructureInfo; public bool UsesAssemblyPreload { get; set; } public string AndroidPackageName { get; set; } public bool JniAddNativeMethodRegistrationAttributePresent { get; set; } - public bool HaveRuntimeConfigBlob { get; set; } public int NumberOfAssembliesInApk { get; set; } public int BundledAssemblyNameWidth { get; set; } // including the trailing NUL public int AndroidRuntimeJNIEnvToken { get; set; } @@ -171,7 +202,8 @@ sealed class XamarinAndroidBundledAssembly public bool MarshalMethodsEnabled { get; set; } public bool IgnoreSplitConfigs { get; set; } - public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary environmentVariables, IDictionary systemProperties, TaskLoggingHelper log) + public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary environmentVariables, IDictionary systemProperties, + IDictionary? runtimeProperties, TaskLoggingHelper log) : base (log) { if (environmentVariables != null) { @@ -181,6 +213,10 @@ public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary if (systemProperties != null) { this.systemProperties = new SortedDictionary (systemProperties, StringComparer.Ordinal); } + + if (runtimeProperties != null) { + this.runtimeProperties = new SortedDictionary (runtimeProperties, StringComparer.Ordinal); + } } protected override void Construct (LlvmIrModule module) @@ -203,9 +239,9 @@ protected override void Construct (LlvmIrModule module) var app_cfg = new ApplicationConfigCLR { uses_assembly_preload = UsesAssemblyPreload, jni_add_native_method_registration_attribute_present = JniAddNativeMethodRegistrationAttributePresent, - have_runtime_config_blob = HaveRuntimeConfigBlob, marshal_methods_enabled = MarshalMethodsEnabled, ignore_split_configs = IgnoreSplitConfigs, + number_of_runtime_properties = (uint)(runtimeProperties == null ? 0 : runtimeProperties.Count), package_naming_policy = (uint)PackageNamingPolicy, environment_variable_count = (uint)(environmentVariables == null ? 0 : environmentVariables.Count * 2), system_property_count = (uint)(systemProperties == null ? 0 : systemProperties.Count * 2), @@ -250,9 +286,77 @@ protected override void Construct (LlvmIrModule module) }; module.Add (bundled_assemblies); + (runtimePropertiesData, runtimePropertyIndex) = InitRuntimeProperties (); + var runtime_properties = new LlvmIrGlobalVariable (runtimePropertiesData, "runtime_properties", LlvmIrVariableOptions.GlobalConstant) { + Comment = "Runtime config properties", + }; + module.Add (runtime_properties); + + var runtime_property_index = new LlvmIrGlobalVariable (runtimePropertyIndex, "runtime_property_index", LlvmIrVariableOptions.GlobalConstant) { + Comment = "Runtime config property index, sorted on property key hash", + BeforeWriteCallback = HashAndSortRuntimePropertiesIndex, + }; + module.Add (runtime_property_index); + AddAssemblyStores (module); } + void HashAndSortRuntimePropertiesIndex (LlvmIrVariable variable, LlvmIrModuleTarget target, object? state) + { + var index = variable.Value as List>; + if (index == null) { + return; + } + + bool is64Bit = target.Is64Bit; + foreach (StructureInstance instance in index) { + if (instance.Obj == null) { + throw new InvalidOperationException ("Internal error: runtime property index must not contain null entries"); + } + + var entry = instance.Obj as RuntimePropertyIndexEntry; + if (entry == null) { + throw new InvalidOperationException ($"Internal error: runtime property index entry has unexpected type {instance.Obj.GetType ()}"); + } + + entry.key_hash = MonoAndroidHelper.GetXxHash (entry.HashedKey, is64Bit); + }; + + index.Sort ((StructureInstance a, StructureInstance b) => a.Instance.key_hash.CompareTo (b.Instance.key_hash)); + } + + (List> runtimeProps, List> runtimePropsIndex) InitRuntimeProperties () + { + var runtimeProps = new List> (); + var runtimePropsIndex = new List> (); + + if (runtimeProperties == null || runtimeProperties.Count == 0) { + return (runtimeProps, runtimePropsIndex); + } + + foreach (var kvp in runtimeProperties) { + string name = kvp.Key; + string value = kvp.Value; + + var prop = new RuntimeProperty { + key = name, + value = value, + + // Includes the terminating NUL + value_size = (uint)(MonoAndroidHelper.Utf8StringToBytes (value).Length + 1), + }; + runtimeProps.Add (new StructureInstance (runtimePropertyStructureInfo, prop)); + + var indexEntry = new RuntimePropertyIndexEntry { + HashedKey = prop.key, + index = (uint)(runtimeProps.Count - 1), + }; + runtimePropsIndex.Add (new StructureInstance (runtimePropertyIndexEntryStructureInfo, indexEntry)); + } + + return (runtimeProps, runtimePropsIndex); + } + void AddAssemblyStores (LlvmIrModule module) { ulong itemCount = (ulong)(NumberOfAssembliesInApk); @@ -384,5 +488,7 @@ void MapStructures (LlvmIrModule module) xamarinAndroidBundledAssemblyStructureInfo = module.MapStructure (); dsoCacheEntryStructureInfo = module.MapStructure (); dsoApkEntryStructureInfo = module.MapStructure (); + runtimePropertyStructureInfo = module.MapStructure (); + runtimePropertyIndexEntryStructureInfo = module.MapStructure (); } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 39a9ccc69c9..0c2d36963d9 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -341,6 +341,10 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. True False + + + False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods) @@ -1807,6 +1811,7 @@ because xbuild doesn't support framework reference assemblies. EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" TargetsCLR="$(_AndroidUseCLR)" + ProjectRuntimeConfigFilePath="$(ProjectRuntimeConfigFilePath)" > diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index bcf6287c233..3fc1b1d222f 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -222,9 +222,9 @@ struct ApplicationConfig { bool uses_assembly_preload; bool jni_add_native_method_registration_attribute_present; - bool have_runtime_config_blob; bool marshal_methods_enabled; bool ignore_split_configs; + uint32_t number_of_runtime_properties; uint32_t package_naming_policy; uint32_t environment_variable_count; uint32_t system_property_count; @@ -241,6 +241,19 @@ struct ApplicationConfig const char *android_package_name; }; +struct RuntimeProperty +{ + const char *key; + const char *value; + uint32_t value_size; // including the terminating NUL +}; + +struct RuntimePropertyIndexEntry +{ + xamarin::android::hash_t key_hash; + uint32_t index; +}; + struct DSOApkEntry { uint64_t name_hash; @@ -323,6 +336,9 @@ extern "C" { [[gnu::visibility("default")]] extern DSOCacheEntry dso_cache[]; [[gnu::visibility("default")]] extern DSOCacheEntry aot_dso_cache[]; [[gnu::visibility("default")]] extern DSOApkEntry dso_apk_entries[]; + + [[gnu::visibility("default")]] extern const RuntimeProperty runtime_properties[]; + [[gnu::visibility("default")]] extern const RuntimePropertyIndexEntry runtime_property_index[]; } // diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 2a34ff4c13d..876f5416dc5 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -44,15 +44,16 @@ constexpr char android_package_name[] = "com.xamarin.test"; const ApplicationConfig application_config = { .uses_assembly_preload = false, .jni_add_native_method_registration_attribute_present = false, - .have_runtime_config_blob = false, .marshal_methods_enabled = false, .ignore_split_configs = false, + .number_of_runtime_properties = 3, .package_naming_policy = 0, .environment_variable_count = 0, .system_property_count = 0, .number_of_assemblies_in_apk = 2, .bundled_assembly_name_width = 0, .number_of_dso_cache_entries = 2, + .number_of_aot_cache_entries = 2, .number_of_shared_libraries = 2, .android_runtime_jnienv_class_token = 1, .jnienv_initialize_method_token = 2, @@ -296,3 +297,44 @@ const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[] = { .replacement = "another/replacement/java/type", }, }; + +constexpr char prop_test_string_key[] = "test_string"; +constexpr char prop_test_integer_key[] = "test_integer"; +constexpr char prop_test_boolean_key[] = "test_boolean"; + +const RuntimeProperty runtime_properties[] = { + { + .key = prop_test_string_key, + .value = "test", + .value_size = sizeof("test"), + }, + + { + .key = prop_test_integer_key, + .value = "42", + .value_size = sizeof("42"), + }, + + { + .key = prop_test_boolean_key, + .value = "true", + .value_size = sizeof("true"), + }, +}; + +const RuntimePropertyIndexEntry runtime_property_index[] = { + { + .key_hash = xamarin::android::xxhash::hash (prop_test_string_key, sizeof(prop_test_string_key) - 1), + .index = 0, + }, + + { + .key_hash = xamarin::android::xxhash::hash (prop_test_integer_key, sizeof(prop_test_integer_key) - 1), + .index = 1, + }, + + { + .key_hash = xamarin::android::xxhash::hash (prop_test_boolean_key, sizeof(prop_test_boolean_key) - 1), + .index = 2, + }, +}; From 552b6c49a261fca1ec4fbe5aa4e5818d21bb41cb Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 27 Jan 2025 22:33:58 +0100 Subject: [PATCH 081/143] [WIP] Unicode strings support --- ...icationConfigNativeAssemblyGeneratorCLR.cs | 54 ++++++++++++- .../LlvmIrGenerator/LlvmIrGenerator.cs | 35 ++++---- .../Utilities/LlvmIrGenerator/LlvmIrModule.cs | 30 +++---- .../LlvmIrGenerator/LlvmIrStringManager.cs | 81 +++++++++++++------ .../LlvmIrGenerator/LlvmIrVariable.cs | 10 +-- .../LlvmIrGenerator/MemberInfoUtilities.cs | 10 --- 6 files changed, 136 insertions(+), 84 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index 7a6dc4b964e..06877d513d4 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -127,6 +127,26 @@ sealed class RuntimePropertyIndexEntry public uint index; } + // Order of fields and their types must correspond **exactly** to those in CoreCLR's host_runtime_contract.h + sealed class host_configuration_property + { + [NativeAssembler (IsUTF16 = true)] + public string name; + + [NativeAssembler (IsUTF16 = true)] + public string value; + } + + // Order of fields and their types must correspond **exactly** to those in CoreCLR's host_runtime_contract.h + const string HostConfigurationPropertiesDataSymbol = "_host_configuration_properties_data"; + sealed class host_configuration_properties + { + public ulong nitems; + + [NativePointer (PointsToSymbol = HostConfigurationPropertiesDataSymbol)] + public host_configuration_property data; + } + sealed class XamarinAndroidBundledAssemblyContextDataProvider : NativeAssemblerStructContextDataProvider { public override ulong GetBufferSize (object data, string fieldName) @@ -177,6 +197,8 @@ sealed class XamarinAndroidBundledAssembly List>? xamarinAndroidBundledAssemblies; List>? runtimePropertiesData; List>? runtimePropertyIndex; + List> hostConfigurationPropertiesData; + StructureInstance hostConfigurationProperties; StructureInfo? applicationConfigStructureInfo; StructureInfo? dsoCacheEntryStructureInfo; @@ -186,6 +208,8 @@ sealed class XamarinAndroidBundledAssembly StructureInfo? assemblyStoreRuntimeDataStructureInfo; StructureInfo? runtimePropertyStructureInfo; StructureInfo? runtimePropertyIndexEntryStructureInfo; + StructureInfo? hostConfigurationPropertyStructureInfo; + StructureInfo? hostConfigurationPropertiesStructureInfo; public bool UsesAssemblyPreload { get; set; } public string AndroidPackageName { get; set; } @@ -286,7 +310,7 @@ protected override void Construct (LlvmIrModule module) }; module.Add (bundled_assemblies); - (runtimePropertiesData, runtimePropertyIndex) = InitRuntimeProperties (); + (runtimePropertiesData, runtimePropertyIndex, hostConfigurationPropertiesData) = InitRuntimeProperties (); var runtime_properties = new LlvmIrGlobalVariable (runtimePropertiesData, "runtime_properties", LlvmIrVariableOptions.GlobalConstant) { Comment = "Runtime config properties", }; @@ -298,6 +322,15 @@ protected override void Construct (LlvmIrModule module) }; module.Add (runtime_property_index); + var hostConfigProps = new host_configuration_properties { + nitems = (ulong)hostConfigurationPropertiesData.Count, + }; + + var _host_configuration_properties_data = new LlvmIrGlobalVariable (hostConfigurationPropertiesData, HostConfigurationPropertiesDataSymbol, LlvmIrVariableOptions.LocalConstant) { + Comment = "Runtime host configuration properties, encoded using 16-bit Unicode, as expected by CoreCLR", + }; + module.Add (_host_configuration_properties_data); + AddAssemblyStores (module); } @@ -325,13 +358,18 @@ void HashAndSortRuntimePropertiesIndex (LlvmIrVariable variable, LlvmIrModuleTar index.Sort ((StructureInstance a, StructureInstance b) => a.Instance.key_hash.CompareTo (b.Instance.key_hash)); } - (List> runtimeProps, List> runtimePropsIndex) InitRuntimeProperties () + ( + List> runtimeProps, + List> runtimePropsIndex, + List> configProps + ) InitRuntimeProperties () { var runtimeProps = new List> (); var runtimePropsIndex = new List> (); + var configProps = new List> (); if (runtimeProperties == null || runtimeProperties.Count == 0) { - return (runtimeProps, runtimePropsIndex); + return (runtimeProps, runtimePropsIndex, configProps); } foreach (var kvp in runtimeProperties) { @@ -352,9 +390,15 @@ void HashAndSortRuntimePropertiesIndex (LlvmIrVariable variable, LlvmIrModuleTar index = (uint)(runtimeProps.Count - 1), }; runtimePropsIndex.Add (new StructureInstance (runtimePropertyIndexEntryStructureInfo, indexEntry)); + + var hostConfigProperty = new host_configuration_property { + name = name, + value = value, + }; + configProps.Add (new StructureInstance (hostConfigurationPropertyStructureInfo, hostConfigProperty)); } - return (runtimeProps, runtimePropsIndex); + return (runtimeProps, runtimePropsIndex, configProps); } void AddAssemblyStores (LlvmIrModule module) @@ -490,5 +534,7 @@ void MapStructures (LlvmIrModule module) dsoApkEntryStructureInfo = module.MapStructure (); runtimePropertyStructureInfo = module.MapStructure (); runtimePropertyIndexEntryStructureInfo = module.MapStructure (); + hostConfigurationPropertyStructureInfo = module.MapStructure (); + hostConfigurationPropertiesStructureInfo = module.MapStructure (); } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs index d8656d09996..6563e3a5cbf 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs @@ -205,6 +205,10 @@ void WriteStrings (GeneratorWriteContext context) WriteCommentLine (context, $" '{info.Value}'"); } + if (!info.IsConstantStringLiteral) { + WriteCommentLine (context, $" '{info.Value}'"); + } + WriteGlobalVariableName (context, info); // Strings must always be local symbols, global variables will point to them @@ -749,7 +753,7 @@ void WriteValue (GeneratorWriteContext context, Type type, object? value, LlvmIr return; } - LlvmIrStringVariable sv = context.Module.LookupRequiredVariableForString (StringHolder.AsHolder (value, stringEncoding)); + LlvmIrStringVariable sv = context.Module.LookupRequiredVariableForString ((string)value, stringEncoding); context.Output.Write (sv.Reference); return; } @@ -1607,19 +1611,16 @@ public static string QuoteStringNoEscape (string s) return $"\"{s}\""; } + delegate string QuoteStringEncoder (byte[] bytes, int byteCount, out ulong stringSize, bool nullTerminated); public static string QuoteString (LlvmIrStringVariable variable, out ulong stringSize, bool nullTerminated = true) { if (variable.Encoding == LlvmIrStringEncoding.UTF8) { - var value = (StringHolder)variable.Value; - if (value.Data == null) { - throw new InvalidOperationException ("Internal error: null strings not supported here, they should be handled elsewhere."); - } - - int byteCount = Encoding.UTF8.GetByteCount (value.Data); + var value = (string)variable.Value; + int byteCount = Encoding.UTF8.GetByteCount (value); var bytes = ArrayPool.Shared.Rent (byteCount); try { - Encoding.UTF8.GetBytes (value.Data, 0, value.Data.Length, bytes, 0); + Encoding.UTF8.GetBytes (value, 0, value.Length, bytes, 0); return QuoteUtf8String (bytes, byteCount, out stringSize, nullTerminated); } finally { ArrayPool.Shared.Return (bytes); @@ -1635,16 +1636,13 @@ public static string QuoteString (LlvmIrStringVariable variable, out ulong strin static string QuoteUnicodeString (LlvmIrStringVariable variable, out ulong stringSize, bool nullTerminated = true) { - var value = (StringHolder)variable.Value; - if (value.Data == null) { - throw new InvalidOperationException ("Internal error: null strings not supported here, they should be handled elsewhere."); - } + var value = (string)variable.Value; // Each character/lexeme is encoded as iXY u0xVXYZ + comma and a space, and on top of that we have two square brackets and a trailing nul - var sb = new StringBuilder ((value.Data.Length * 13) + 3); // rough estimate of capacity + var sb = new StringBuilder ((value.Length * 13) + 3); // rough estimate of capacity sb.Append ('['); - for (int i = 0; i < value.Data.Length; i++) { - var ch = (short)value.Data[i]; + for (int i = 0; i < value.Length; i++) { + var ch = (short)value[i]; if (i > 0) { sb.Append (", "); } @@ -1652,14 +1650,11 @@ static string QuoteUnicodeString (LlvmIrStringVariable variable, out ulong strin } if (nullTerminated) { - if (value.Data.Length > 0) { - sb.Append (", "); - } - sb.Append ($"{variable.IrType} 0"); + sb.Append ($", {variable.IrType} 0"); } sb.Append (']'); - stringSize = (ulong)value.Data.Length + (nullTerminated ? 1u : 0u); + stringSize = (ulong)value.Length + (nullTerminated ? 1u : 0u); return sb.ToString (); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs index 163e60ed51c..b536c87dff5 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs @@ -49,8 +49,6 @@ partial class LlvmIrModule public readonly LlvmIrTypeCache TypeCache; - public string? DefaultStringGroup { get; set; } - public LlvmIrModule (LlvmIrTypeCache cache, TaskLoggingHelper log) { this.log = log; @@ -404,30 +402,20 @@ void AddStandardGlobalVariable (LlvmIrGlobalVariable variable) globalVariables.Add (variable); } - void EnsureStringManager () - { - if (stringManager == null) { - stringManager = new LlvmIrStringManager (log, DefaultStringGroup); - } - } - void AddStringGlobalVariable (LlvmIrStringVariable variable, string? stringGroupName = null, string? stringGroupComment = null, string? symbolSuffix = null) { - RegisterString (variable, stringGroupName, stringGroupComment, symbolSuffix); + RegisterString ((string)variable.Value, stringGroupName, stringGroupComment, symbolSuffix, variable.Encoding); AddStandardGlobalVariable (variable); } - public void RegisterString (LlvmIrStringVariable variable, string? stringGroupName = null, string? stringGroupComment = null, string? symbolSuffix = null) - { - EnsureStringManager (); - stringManager.Add (variable, stringGroupName, stringGroupComment, symbolSuffix); - } - public void RegisterString (string value, string? stringGroupName = null, string? stringGroupComment = null, string? symbolSuffix = null, - LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8, StringComparison comparison = StringComparison.Ordinal) + LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8) { - EnsureStringManager (); - stringManager.Add (value, stringGroupName, stringGroupComment, symbolSuffix, encoding, comparison); + if (stringManager == null) { + stringManager = new LlvmIrStringManager (log); + } + + stringManager.Add (value, stringGroupName, stringGroupComment, symbolSuffix, encoding); } void AddStructureArrayGlobalVariable (LlvmIrGlobalVariable variable) @@ -592,9 +580,9 @@ void EnsureValidGlobalVariableType (LlvmIrGlobalVariable variable) /// are part of structure instances. Such strings **MUST** be registered by and, thus, failure to do /// so is an internal error. /// - public LlvmIrStringVariable LookupRequiredVariableForString (StringHolder value) + public LlvmIrStringVariable LookupRequiredVariableForString (string value, LlvmIrStringEncoding encoding) { - LlvmIrStringVariable? sv = stringManager?.Lookup (value); + LlvmIrStringVariable? sv = stringManager?.Lookup (value, encoding); if (sv == null) { throw new InvalidOperationException ($"Internal error: string '{value}' wasn't registered with string manager"); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs index 7290a87a5f5..fa2c6ff678f 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs @@ -9,9 +9,44 @@ partial class LlvmIrModule { protected class LlvmIrStringManager { - readonly string defaultGroupName = "str"; + sealed class ByteArrayEqualityComparer : EqualityComparer + { + public override bool Equals (byte [] x, byte [] y) + { + if (x == null || y == null) { + return x == y; + } + + if (ReferenceEquals (x, y)) { + return true; + } + + if (x.Length != y.Length) { + return false; + } + + if (x.Length == 0) { + return true; + } + + for (int i = 0; i < x.Length; i++) { + if (x[i] != y[i]) { + return false; + } + } + + return true; + } + + public override int GetHashCode (byte [] obj) + { + return 0; // force use of Equals + } + } - Dictionary stringSymbolCache = new Dictionary (); + // A byte array is needed for caching since it's possible that we might have two distinct variables + // with the same string, only encoded in different encodings. Slow... + Dictionary stringSymbolCache = new Dictionary (new ByteArrayEqualityComparer ()); Dictionary stringGroupCache = new Dictionary (StringComparer.Ordinal); List stringGroups = new List (); @@ -20,37 +55,24 @@ protected class LlvmIrStringManager public List StringGroups => stringGroups; - public LlvmIrStringManager (TaskLoggingHelper log, string? defaultStringGroup = null) + public LlvmIrStringManager (TaskLoggingHelper log) { this.log = log; - if (!String.IsNullOrEmpty (defaultStringGroup)) { - defaultGroupName = defaultStringGroup; - } - defaultGroup = new LlvmIrStringGroup (); stringGroupCache.Add (String.Empty, defaultGroup); stringGroups.Add (defaultGroup); } - public LlvmIrStringVariable Add (LlvmIrStringVariable variable, string? groupName = null, string? groupComment = null, string? symbolSuffix = null) - { - // Let it throw if Value isn't a StringHolder, it must be. - return Add((StringHolder)variable.Value, groupName, groupComment, symbolSuffix); - } - public LlvmIrStringVariable Add (string value, string? groupName = null, string? groupComment = null, string? symbolSuffix = null, - LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8, StringComparison comparison = StringComparison.Ordinal) + LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8) { if (value == null) { throw new ArgumentNullException (nameof (value)); } - return Add (new StringHolder (value, encoding, comparison), groupName, groupComment, symbolSuffix); - } - - LlvmIrStringVariable Add (StringHolder holder, string? groupName = null, string? groupComment = null, string? symbolSuffix = null) - { - if (stringSymbolCache.TryGetValue (holder, out LlvmIrStringVariable? stringVar) && stringVar != null) { + byte[] valueBytes = GetStringBytes (value, encoding); + LlvmIrStringVariable? stringVar; + if (stringSymbolCache.TryGetValue (valueBytes, out stringVar) && stringVar != null) { return stringVar; } @@ -73,20 +95,31 @@ LlvmIrStringVariable Add (StringHolder holder, string? groupName = null, string? symbolName = $"{symbolName}_{symbolSuffix}"; } - stringVar = new LlvmIrStringVariable (symbolName, holder); + stringVar = new LlvmIrStringVariable (symbolName, value, encoding); group.Strings.Add (stringVar); - stringSymbolCache.Add (holder, stringVar); + stringSymbolCache.Add (valueBytes, stringVar); return stringVar; } - public LlvmIrStringVariable? Lookup (StringHolder value) + // TODO: introduce a "string holder" type which will keep the encoding alongside the actual value + public LlvmIrStringVariable? Lookup (string value, LlvmIrStringEncoding encoding) { - if (stringSymbolCache.TryGetValue (value, out LlvmIrStringVariable? sv)) { + byte[] valueBytes = GetStringBytes (value, encoding); + if (stringSymbolCache.TryGetValue (valueBytes, out LlvmIrStringVariable? sv)) { return sv; } return null; } + + byte[] GetStringBytes (string value, LlvmIrStringEncoding encoding) + { + return encoding switch { + LlvmIrStringEncoding.UTF8 => MonoAndroidHelper.Utf8StringToBytes (value), + LlvmIrStringEncoding.Unicode => MonoAndroidHelper.Utf16StringToBytes (value), + _ => throw new InvalidOperationException ($"Internal error: unsupported encoding '{encoding}'") + }; + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs index 07badc4fd2c..0b94109a58f 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs @@ -301,13 +301,13 @@ class LlvmIrStringVariable : LlvmIrGlobalVariable public string IrType { get; } public bool IsConstantStringLiteral { get; } - public LlvmIrStringVariable (string name, StringHolder value, LlvmIrVariableOptions? options = null) - : base (typeof(string), name, options ?? LlvmIrVariableOptions.GlobalConstantStringPointer) + public LlvmIrStringVariable (string name, string value, LlvmIrStringEncoding encoding) + : base (typeof(string), name, LlvmIrVariableOptions.LocalString) { Value = value; - Encoding = value.Encoding; + Encoding = encoding; - switch (value.Encoding) { + switch (encoding) { case LlvmIrStringEncoding.UTF8: IrType = "i8"; IsConstantStringLiteral = true; @@ -318,7 +318,7 @@ public LlvmIrStringVariable (string name, StringHolder value, LlvmIrVariableOpti break; default: - throw new InvalidOperationException ($"Internal error: unsupported string encoding {value.Encoding}"); + throw new InvalidOperationException ($"Internal error: unsupported string encoding {encoding}"); } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs index aac8b8b3636..920a9073750 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs @@ -34,16 +34,6 @@ public static bool PointsToSymbol (this MemberInfo mi, LlvmIrTypeCache cache, ou return true; } - public static bool IsUnicodeString (this MemberInfo mi, LlvmIrTypeCache cache) - { - var attr = cache.GetNativeAssemblerAttribute (mi); - if (attr == null) { - return false; - } - - return attr.IsUTF16; - } - public static LlvmIrStringEncoding GetStringEncoding (this MemberInfo mi, LlvmIrTypeCache cache) { const LlvmIrStringEncoding DefaultStringEncoding = LlvmIrStringEncoding.UTF8; From 5fab337cbbd6fdfd7527e7a132f88484a79853fc Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 28 Jan 2025 12:07:58 +0100 Subject: [PATCH 082/143] More elegant solution to managing same strings with different encodings --- .../LlvmIrGenerator/LlvmIrGenerator.cs | 31 +++++---- .../Utilities/LlvmIrGenerator/LlvmIrModule.cs | 8 +-- .../LlvmIrGenerator/LlvmIrStringManager.cs | 65 +++---------------- .../LlvmIrGenerator/LlvmIrVariable.cs | 12 ++-- .../LlvmIrGenerator/MemberInfoUtilities.cs | 10 +++ .../Utilities/LlvmIrGenerator/StringHolder.cs | 56 ++++++++++------ 6 files changed, 84 insertions(+), 98 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs index 6563e3a5cbf..d91d8faae50 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs @@ -753,7 +753,7 @@ void WriteValue (GeneratorWriteContext context, Type type, object? value, LlvmIr return; } - LlvmIrStringVariable sv = context.Module.LookupRequiredVariableForString ((string)value, stringEncoding); + LlvmIrStringVariable sv = context.Module.LookupRequiredVariableForString (StringHolder.AsHolder (value, stringEncoding)); context.Output.Write (sv.Reference); return; } @@ -1611,16 +1611,19 @@ public static string QuoteStringNoEscape (string s) return $"\"{s}\""; } - delegate string QuoteStringEncoder (byte[] bytes, int byteCount, out ulong stringSize, bool nullTerminated); public static string QuoteString (LlvmIrStringVariable variable, out ulong stringSize, bool nullTerminated = true) { if (variable.Encoding == LlvmIrStringEncoding.UTF8) { - var value = (string)variable.Value; - int byteCount = Encoding.UTF8.GetByteCount (value); + var value = (StringHolder)variable.Value; + if (value.Data == null) { + throw new InvalidOperationException ("Internal error: null strings not supported here, they should be handled elsewhere."); + } + + int byteCount = Encoding.UTF8.GetByteCount (value.Data); var bytes = ArrayPool.Shared.Rent (byteCount); try { - Encoding.UTF8.GetBytes (value, 0, value.Length, bytes, 0); + Encoding.UTF8.GetBytes (value.Data, 0, value.Data.Length, bytes, 0); return QuoteUtf8String (bytes, byteCount, out stringSize, nullTerminated); } finally { ArrayPool.Shared.Return (bytes); @@ -1636,13 +1639,16 @@ public static string QuoteString (LlvmIrStringVariable variable, out ulong strin static string QuoteUnicodeString (LlvmIrStringVariable variable, out ulong stringSize, bool nullTerminated = true) { - var value = (string)variable.Value; + var value = (StringHolder)variable.Value; + if (value.Data == null) { + throw new InvalidOperationException ("Internal error: null strings not supported here, they should be handled elsewhere."); + } // Each character/lexeme is encoded as iXY u0xVXYZ + comma and a space, and on top of that we have two square brackets and a trailing nul - var sb = new StringBuilder ((value.Length * 13) + 3); // rough estimate of capacity + var sb = new StringBuilder ((value.Data.Length * 13) + 3); // rough estimate of capacity sb.Append ('['); - for (int i = 0; i < value.Length; i++) { - var ch = (short)value[i]; + for (int i = 0; i < value.Data.Length; i++) { + var ch = (short)value.Data[i]; if (i > 0) { sb.Append (", "); } @@ -1650,11 +1656,14 @@ static string QuoteUnicodeString (LlvmIrStringVariable variable, out ulong strin } if (nullTerminated) { - sb.Append ($", {variable.IrType} 0"); + if (value.Data.Length > 0) { + sb.Append (", "); + } + sb.Append ($"{variable.IrType} 0"); } sb.Append (']'); - stringSize = (ulong)value.Length + (nullTerminated ? 1u : 0u); + stringSize = (ulong)value.Data.Length + (nullTerminated ? 1u : 0u); return sb.ToString (); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs index b536c87dff5..fe2914262f2 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs @@ -409,13 +409,13 @@ void AddStringGlobalVariable (LlvmIrStringVariable variable, string? stringGroup } public void RegisterString (string value, string? stringGroupName = null, string? stringGroupComment = null, string? symbolSuffix = null, - LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8) + LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8, StringComparison comparison = StringComparison.Ordinal) { if (stringManager == null) { stringManager = new LlvmIrStringManager (log); } - stringManager.Add (value, stringGroupName, stringGroupComment, symbolSuffix, encoding); + stringManager.Add (value, stringGroupName, stringGroupComment, symbolSuffix, encoding, comparison); } void AddStructureArrayGlobalVariable (LlvmIrGlobalVariable variable) @@ -580,9 +580,9 @@ void EnsureValidGlobalVariableType (LlvmIrGlobalVariable variable) /// are part of structure instances. Such strings **MUST** be registered by and, thus, failure to do /// so is an internal error. /// - public LlvmIrStringVariable LookupRequiredVariableForString (string value, LlvmIrStringEncoding encoding) + public LlvmIrStringVariable LookupRequiredVariableForString (StringHolder value) { - LlvmIrStringVariable? sv = stringManager?.Lookup (value, encoding); + LlvmIrStringVariable? sv = stringManager?.Lookup (value); if (sv == null) { throw new InvalidOperationException ($"Internal error: string '{value}' wasn't registered with string manager"); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs index fa2c6ff678f..917ce8e4b1d 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs @@ -9,44 +9,7 @@ partial class LlvmIrModule { protected class LlvmIrStringManager { - sealed class ByteArrayEqualityComparer : EqualityComparer - { - public override bool Equals (byte [] x, byte [] y) - { - if (x == null || y == null) { - return x == y; - } - - if (ReferenceEquals (x, y)) { - return true; - } - - if (x.Length != y.Length) { - return false; - } - - if (x.Length == 0) { - return true; - } - - for (int i = 0; i < x.Length; i++) { - if (x[i] != y[i]) { - return false; - } - } - - return true; - } - - public override int GetHashCode (byte [] obj) - { - return 0; // force use of Equals - } - } - - // A byte array is needed for caching since it's possible that we might have two distinct variables - // with the same string, only encoded in different encodings. Slow... - Dictionary stringSymbolCache = new Dictionary (new ByteArrayEqualityComparer ()); + Dictionary stringSymbolCache = new Dictionary (); Dictionary stringGroupCache = new Dictionary (StringComparer.Ordinal); List stringGroups = new List (); @@ -64,15 +27,14 @@ public LlvmIrStringManager (TaskLoggingHelper log) } public LlvmIrStringVariable Add (string value, string? groupName = null, string? groupComment = null, string? symbolSuffix = null, - LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8) + LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8, StringComparison comparison = StringComparison.Ordinal) { if (value == null) { throw new ArgumentNullException (nameof (value)); } - byte[] valueBytes = GetStringBytes (value, encoding); - LlvmIrStringVariable? stringVar; - if (stringSymbolCache.TryGetValue (valueBytes, out stringVar) && stringVar != null) { + var holder = new StringHolder (value, encoding, comparison); + if (stringSymbolCache.TryGetValue (holder, out LlvmIrStringVariable? stringVar) && stringVar != null) { return stringVar; } @@ -95,31 +57,20 @@ public LlvmIrStringVariable Add (string value, string? groupName = null, string? symbolName = $"{symbolName}_{symbolSuffix}"; } - stringVar = new LlvmIrStringVariable (symbolName, value, encoding); + stringVar = new LlvmIrStringVariable (symbolName, holder); group.Strings.Add (stringVar); - stringSymbolCache.Add (valueBytes, stringVar); + stringSymbolCache.Add (holder, stringVar); return stringVar; } - // TODO: introduce a "string holder" type which will keep the encoding alongside the actual value - public LlvmIrStringVariable? Lookup (string value, LlvmIrStringEncoding encoding) + public LlvmIrStringVariable? Lookup (StringHolder value) { - byte[] valueBytes = GetStringBytes (value, encoding); - if (stringSymbolCache.TryGetValue (valueBytes, out LlvmIrStringVariable? sv)) { + if (stringSymbolCache.TryGetValue (value, out LlvmIrStringVariable? sv)) { return sv; } return null; } - - byte[] GetStringBytes (string value, LlvmIrStringEncoding encoding) - { - return encoding switch { - LlvmIrStringEncoding.UTF8 => MonoAndroidHelper.Utf8StringToBytes (value), - LlvmIrStringEncoding.Unicode => MonoAndroidHelper.Utf16StringToBytes (value), - _ => throw new InvalidOperationException ($"Internal error: unsupported encoding '{encoding}'") - }; - } } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs index 0b94109a58f..d6571f3760e 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs @@ -301,13 +301,13 @@ class LlvmIrStringVariable : LlvmIrGlobalVariable public string IrType { get; } public bool IsConstantStringLiteral { get; } - public LlvmIrStringVariable (string name, string value, LlvmIrStringEncoding encoding) + public LlvmIrStringVariable (string name, StringHolder value) : base (typeof(string), name, LlvmIrVariableOptions.LocalString) { Value = value; - Encoding = encoding; + Encoding = value.Encoding; - switch (encoding) { + switch (value.Encoding) { case LlvmIrStringEncoding.UTF8: IrType = "i8"; IsConstantStringLiteral = true; @@ -318,12 +318,12 @@ public LlvmIrStringVariable (string name, string value, LlvmIrStringEncoding enc break; default: - throw new InvalidOperationException ($"Internal error: unsupported string encoding {encoding}"); + throw new InvalidOperationException ($"Internal error: unsupported string encoding {value.Encoding}"); } } - public LlvmIrStringVariable (string name, string value, LlvmIrStringEncoding encoding, StringComparison comparison = StringComparison.Ordinal, LlvmIrVariableOptions? options = null) - : this (name, new StringHolder (value, encoding, comparison), options) + public LlvmIrStringVariable (string name, string value, LlvmIrStringEncoding encoding, StringComparison comparison = StringComparison.Ordinal) + : this (name, new StringHolder (value, encoding, comparison)) {} } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs index 920a9073750..aac8b8b3636 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/MemberInfoUtilities.cs @@ -34,6 +34,16 @@ public static bool PointsToSymbol (this MemberInfo mi, LlvmIrTypeCache cache, ou return true; } + public static bool IsUnicodeString (this MemberInfo mi, LlvmIrTypeCache cache) + { + var attr = cache.GetNativeAssemblerAttribute (mi); + if (attr == null) { + return false; + } + + return attr.IsUTF16; + } + public static LlvmIrStringEncoding GetStringEncoding (this MemberInfo mi, LlvmIrTypeCache cache) { const LlvmIrStringEncoding DefaultStringEncoding = LlvmIrStringEncoding.UTF8; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs index 1043f1dc145..cbcfd02c9d8 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs @@ -34,7 +34,15 @@ public static StringHolder AsHolder (object? value, LlvmIrStringEncoding encodin return holder; } - public int CompareTo (object obj) => CompareTo (obj as StringHolder); + public int CompareTo (object obj) + { + var holder = obj as StringHolder; + if (holder == null) { + return 1; + } + + return CompareTo (holder); + } public int CompareTo (StringHolder? other) { @@ -75,7 +83,15 @@ public override int GetHashCode () return hc ^ Encoding.GetHashCode (); } - public override bool Equals (object obj) => Equals (obj as StringHolder); + public override bool Equals (object obj) + { + var holder = obj as StringHolder; + if (holder == null) { + return false; + } + + return Equals (holder); + } public bool Equals (StringHolder? other) { @@ -87,22 +103,22 @@ public bool Equals (StringHolder? other) } public static bool operator > (StringHolder a, StringHolder b) - { - return a.CompareTo (b) > 0; - } - - public static bool operator < (StringHolder a, StringHolder b) - { - return a.CompareTo (b) < 0; - } - - public static bool operator >= (StringHolder a, StringHolder b) - { - return a.CompareTo (b) >= 0; - } - - public static bool operator <= (StringHolder a, StringHolder b) - { - return a.CompareTo (b) <= 0; - } + { + return a.CompareTo (b) > 0; + } + + public static bool operator < (StringHolder a, StringHolder b) + { + return a.CompareTo (b) < 0; + } + + public static bool operator >= (StringHolder a, StringHolder b) + { + return a.CompareTo (b) >= 0; + } + + public static bool operator <= (StringHolder a, StringHolder b) + { + return a.CompareTo (b) <= 0; + } } From a8fc7dfe1caadb3bbbc55a715ff3c75372c2912d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 28 Jan 2025 15:14:21 +0100 Subject: [PATCH 083/143] Add a missing variable --- ...pplicationConfigNativeAssemblyGeneratorCLR.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index 06877d513d4..d2a5670c20c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -322,14 +322,22 @@ protected override void Construct (LlvmIrModule module) }; module.Add (runtime_property_index); + var _host_configuration_properties_data = new LlvmIrGlobalVariable (hostConfigurationPropertiesData, HostConfigurationPropertiesDataSymbol, LlvmIrVariableOptions.LocalConstant) { + Comment = "Runtime host configuration properties data, encoded using 16-bit Unicode, as expected by CoreCLR", + }; + module.Add (_host_configuration_properties_data); + var hostConfigProps = new host_configuration_properties { nitems = (ulong)hostConfigurationPropertiesData.Count, }; - - var _host_configuration_properties_data = new LlvmIrGlobalVariable (hostConfigurationPropertiesData, HostConfigurationPropertiesDataSymbol, LlvmIrVariableOptions.LocalConstant) { - Comment = "Runtime host configuration properties, encoded using 16-bit Unicode, as expected by CoreCLR", + var host_config_props = new LlvmIrGlobalVariable ( + new StructureInstance (hostConfigurationPropertiesStructureInfo, hostConfigProps), + "host_configuration_properties", + LlvmIrVariableOptions.GlobalConstant) + { + Comment = "Runtime host config properties, for CoreCLR initialization phase" }; - module.Add (_host_configuration_properties_data); + module.Add (host_config_props); AddAssemblyStores (module); } From a7d384f80e7849ddb899013c101de0312c903c37 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 28 Jan 2025 22:10:20 +0100 Subject: [PATCH 084/143] One step closer --- ...icationConfigNativeAssemblyGeneratorCLR.cs | 2 +- src/native/CMakeLists.txt | 7 ---- src/native/clr/host/host.cc | 33 ++++++++++++++++++- src/native/clr/include/host/host.hh | 15 +++++++++ src/native/clr/include/xamarin-app.hh | 3 ++ src/native/clr/shared/helpers.cc | 2 +- .../xamarin-app-stub/application_dso_stub.cc | 24 ++++++++++++++ 7 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index d2a5670c20c..b528906e3ed 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -332,7 +332,7 @@ protected override void Construct (LlvmIrModule module) }; var host_config_props = new LlvmIrGlobalVariable ( new StructureInstance (hostConfigurationPropertiesStructureInfo, hostConfigProps), - "host_configuration_properties", + "host_config_properties", LlvmIrVariableOptions.GlobalConstant) { Comment = "Runtime host config properties, for CoreCLR initialization phase" diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 8a7878d2200..fe0c17d9607 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -260,13 +260,6 @@ macro(xa_add_compile_definitions TARGET) ${TARGET} PRIVATE TARGET_ANDROID - XA_HOST_CLR - ) - else() - target_compile_definitions( - ${TARGET} - PRIVATE - XA_HOST_MONOVM ) endif() endmacro() diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 02d0dd4d273..e5492912b62 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -1,5 +1,6 @@ -#include +#include +#include #include #include #include @@ -10,6 +11,25 @@ using namespace xamarin::android; +size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept +{ + log_info (LOG_DEFAULT, "clr_get_runtime_property (\"{}\"...)", key); + return 0; +} + +bool Host::clr_bundle_probe (const char *path, int64_t *offset, int64_t *size, int64_t *compressedSize) noexcept +{ + log_info (LOG_DEFAULT, "clr_bundle_probe (\"{}\"...)", path); + Helpers::abort_application ("Gimme stack trace"); + return false; +} + +const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept +{ + log_info (LOG_DEFAULT, "clr_pinvoke_override (\"{}\", \"{}\")", library_name, entry_point_name); + return nullptr; +} + void Host::create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept { static_local_string dir (home_len + relative_path.length ()); @@ -70,6 +90,17 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, js AndroidSystem::create_update_dir (AndroidSystem::get_primary_override_dir ()); AndroidSystem::setup_environment (); + log_write (LOG_DEFAULT, LogLevel::Info, "Calling CoreCLR initialization routine"); + android_coreclr_initialize ( + application_config.android_package_name, + u"Xamarin.Android", + &runtime_contract, + &host_config_properties, + &clr_host, + &domain_id + ); + log_write (LOG_DEFAULT, LogLevel::Info, "CoreCLR initialization routine returned"); + if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (total_time_index); } diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 347e318e6c8..67f97e16b2a 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -3,6 +3,7 @@ #include #include +#include #include "../runtime-base/jni-wrappers.hh" #include "../runtime-base/timing.hh" @@ -26,7 +27,21 @@ namespace xamarin::android { static void create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept; static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept; + static size_t clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept; + static bool clr_bundle_probe (const char *path, int64_t *offset, int64_t *size, int64_t *compressedSize) noexcept; + static const void* clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept; + private: + static inline void *clr_host = nullptr; + static inline unsigned int domain_id = 0; static inline std::unique_ptr _timing{}; + + static inline host_runtime_contract runtime_contract{ + .size = sizeof(host_runtime_contract), + .context = nullptr, + .get_runtime_property = clr_get_runtime_property, + .bundle_probe = clr_bundle_probe, + .pinvoke_override = clr_pinvoke_override, + }; }; } diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index 3fc1b1d222f..558fa42d9d1 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -4,6 +4,7 @@ #include #include +#include #include "shared/xxhash.hh" @@ -339,6 +340,8 @@ extern "C" { [[gnu::visibility("default")]] extern const RuntimeProperty runtime_properties[]; [[gnu::visibility("default")]] extern const RuntimePropertyIndexEntry runtime_property_index[]; + + [[gnu::visibility("default")]] extern const host_configuration_properties host_config_properties; } // diff --git a/src/native/clr/shared/helpers.cc b/src/native/clr/shared/helpers.cc index 59697e7d257..7850592af5a 100644 --- a/src/native/clr/shared/helpers.cc +++ b/src/native/clr/shared/helpers.cc @@ -35,7 +35,7 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - "Abort at {}:{}:{} ('%s')", + "Abort at {}:{}:{} ('{}')", file_name, sloc.line (), sloc.column (), diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 876f5416dc5..0e355298d40 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -338,3 +338,27 @@ const RuntimePropertyIndexEntry runtime_property_index[] = { .index = 2, }, }; + +namespace { + const host_configuration_property _host_configuration_properties_data[] = { + { + .name = u"test_string", + .value = u"string value", + }, + + { + .name = u"test_integer", + .value = u"23", + }, + + { + .name = u"test_boolean", + .value = u"true", + }, + }; +} + +const host_configuration_properties host_config_properties = { + .nitems = 3, + .data = _host_configuration_properties_data, +}; From cc3e52887a17bf958bc599efff376e442d0849ef Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 29 Jan 2025 22:57:11 +0100 Subject: [PATCH 085/143] More work towards assembly store support in CLR --- CLR-Host-Notes.md | 13 + .../Xamarin.Android.Common.targets | 18 +- src/native/clr/host/host.cc | 17 +- src/native/clr/include/host/host.hh | 5 +- .../include/runtime-base/android-system.hh | 25 + src/native/clr/include/startup/zip.hh | 84 ++- src/native/clr/runtime-base/CMakeLists.txt | 1 + src/native/clr/runtime-base/android-system.cc | 75 +++ src/native/clr/startup/zip.cc | 477 ++++++++++++++++++ 9 files changed, 686 insertions(+), 29 deletions(-) create mode 100644 CLR-Host-Notes.md diff --git a/CLR-Host-Notes.md b/CLR-Host-Notes.md new file mode 100644 index 00000000000..535d98d59a6 --- /dev/null +++ b/CLR-Host-Notes.md @@ -0,0 +1,13 @@ +# Notes + +## Potential optimizations + + * https://github.com/dotnet/runtime/blob/9b24fb60a19f62620ca1fc5e4eb2e3ae0b3b086d/src/coreclr/binder/assemblybindercommon.cpp#L844-L889 + * Managed C++ assemblies aren't available on Unix, no point in looking for them + * `candidates[]` is `WCHAR*`, while `ProbeAppBundle` takes UTF-8 - no point in doing the + conversion here + * Host contract + * It might make sense to pass strings as Unicode to host and back, to avoid conversions. + p/invoke names for instance, can be Unicode. So can be the assembly names. Native library + names should be UTF-8, but we can generate lookup tables for those at application build time + (e.g. indexed by an xxHash of the Unicode version of the name) - no conversion at run time. diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 0c2d36963d9..82c1156fe1a 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2238,23 +2238,9 @@ because xbuild doesn't support framework reference assemblies. - - - - + #include #include +#include using namespace xamarin::android; @@ -17,10 +18,13 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size return 0; } -bool Host::clr_bundle_probe (const char *path, int64_t *offset, int64_t *size, int64_t *compressedSize) noexcept +bool Host::clr_bundle_probe (const char *path, void **data_start, int64_t *size) noexcept { log_info (LOG_DEFAULT, "clr_bundle_probe (\"{}\"...)", path); - Helpers::abort_application ("Gimme stack trace"); + if (data_start == nullptr || size == nullptr) { + return false; // TODO: abort instead? + } + return false; } @@ -30,6 +34,10 @@ const void* Host::clr_pinvoke_override (const char *library_name, const char *en return nullptr; } +void Host::gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks) +{ +} + void Host::create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept { static_local_string dir (home_len + relative_path.length ()); @@ -90,6 +98,11 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, js AndroidSystem::create_update_dir (AndroidSystem::get_primary_override_dir ()); AndroidSystem::setup_environment (); + jstring_array_wrapper runtimeApks (env, runtimeApksJava); + AndroidSystem::setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); + + gather_assemblies_and_libraries (runtimeApks, haveSplitApks); + log_write (LOG_DEFAULT, LogLevel::Info, "Calling CoreCLR initialization routine"); android_coreclr_initialize ( application_config.android_package_name, diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 67f97e16b2a..a1489671009 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -26,9 +26,10 @@ namespace xamarin::android { private: static void create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept; static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept; + static void gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks); static size_t clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept; - static bool clr_bundle_probe (const char *path, int64_t *offset, int64_t *size, int64_t *compressedSize) noexcept; + static bool clr_bundle_probe (const char *path, void **data_start, int64_t *size) noexcept; static const void* clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept; private: @@ -40,7 +41,7 @@ namespace xamarin::android { .size = sizeof(host_runtime_contract), .context = nullptr, .get_runtime_property = clr_get_runtime_property, - .bundle_probe = clr_bundle_probe, + .android_bundle_probe = clr_bundle_probe, .pinvoke_override = clr_pinvoke_override, }; }; diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index cf21b566dca..3e9546e0dcf 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -1,11 +1,13 @@ #pragma once +#include #include #include #include #include "../constants.hh" #include "../shared/log_types.hh" +#include "../runtime-base/cpu-arch.hh" #include "jni-wrappers.hh" #include "strings.hh" #include "util.hh" @@ -15,6 +17,21 @@ struct BundledProperty; namespace xamarin::android { class AndroidSystem { + // 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; + + static constexpr std::array android_abi_names { + std::string_view { "unknown" }, // CPU_KIND_UNKNOWN + std::string_view { "armeabi-v7a" }, // CPU_KIND_ARM + std::string_view { "arm64-v8a" }, // CPU_KIND_ARM64 + std::string_view { "mips" }, // CPU_KIND_MIPS + std::string_view { "x86" }, // CPU_KIND_X86 + std::string_view { "x86_64" }, // CPU_KIND_X86_64 + std::string_view { "riscv" }, // CPU_KIND_RISCV + }; + public: static auto get_max_gref_count () noexcept -> long { @@ -64,11 +81,14 @@ namespace xamarin::android { static auto monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int; static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; static void setup_environment () noexcept; + static void setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) noexcept; private: static auto lookup_system_property (std::string_view const &name, size_t &value_len) noexcept -> const char*; static auto monodroid__system_property_get (std::string_view const&, char *sp_value, size_t sp_value_len) noexcept -> int; static auto get_max_gref_count_from_system () noexcept -> long; + static void add_apk_libdir (std::string_view const& apk, size_t &index, std::string_view const& abi) noexcept; + static void setup_apk_directories (unsigned short running_on_cpu, jstring_array_wrapper &runtimeApks, bool have_split_apks) noexcept; #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; @@ -80,6 +100,11 @@ namespace xamarin::android { embedded_dso_mode_enabled = yesno; } + static auto is_embedded_dso_mode_enabled () noexcept -> bool + { + return embedded_dso_mode_enabled; + } + static auto determine_primary_override_dir (jstring_wrapper &home) noexcept -> std::string { dynamic_local_string name { home.get_cstr () }; diff --git a/src/native/clr/include/startup/zip.hh b/src/native/clr/include/startup/zip.hh index 96afac707bd..d9cf64ed269 100644 --- a/src/native/clr/include/startup/zip.hh +++ b/src/native/clr/include/startup/zip.hh @@ -2,30 +2,96 @@ #include +#include #include #include #include +#include namespace xamarin::android { + namespace detail { + template + concept ByteArrayContainer = requires (T a) { + a.size (); + a.data (); + requires std::same_as; + }; + } + class Zip { + public: + // Returns `true` if the entry was something we need. + using ScanCallbackFn = bool(const char *apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size); + + struct zip_scan_state + { + int file_fd; + const char * file_name; + const char * const prefix; + uint32_t prefix_len; + size_t buf_offset; + uint16_t compression_method; + uint32_t local_header_offset; + uint32_t data_offset; + uint32_t file_size; + bool bundled_assemblies_slow_path; + uint32_t max_assembly_name_size; + uint32_t max_assembly_file_name_size; + }; + private: - static inline constexpr off_t ZIP_EOCD_LEN = 22; - static inline constexpr off_t ZIP_CENTRAL_LEN = 46; - static inline constexpr off_t ZIP_LOCAL_LEN = 30; + static inline constexpr off_t ZIP_EOCD_LEN = 22; + static inline constexpr off_t ZIP_CENTRAL_LEN = 46; + static inline constexpr off_t ZIP_LOCAL_LEN = 30; static inline constexpr std::string_view ZIP_CENTRAL_MAGIC { "PK\1\2" }; static inline constexpr std::string_view ZIP_LOCAL_MAGIC { "PK\3\4" }; - static inline constexpr std::string_view ZIP_EOCD_MAGIC { "PK\5\6" }; + static inline constexpr std::string_view ZIP_EOCD_MAGIC { "PK\5\6" }; - static constexpr std::string_view zip_path_separator { "/" }; - static constexpr std::string_view apk_lib_dir_name { "lib" }; + static constexpr std::string_view zip_path_separator { "/" }; + static constexpr std::string_view apk_lib_dir_name { "lib" }; - static constexpr size_t assemblies_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); - static constexpr auto assemblies_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); + static constexpr size_t lib_prefix_size = calc_size(apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); + static constexpr auto lib_prefix_array = concat_string_views (apk_lib_dir_name, zip_path_separator, Constants::android_lib_abi, zip_path_separator); // .data() must be used otherwise string_view length will include the trailing \0 in the array - static constexpr std::string_view assemblies_prefix { assemblies_prefix_array.data () }; + static constexpr std::string_view lib_prefix { lib_prefix_array.data () }; + + public: + // Scans the ZIP archive for any entries matching the `lib/{ARCH}/` prefix and calls `entry_cb` + // for each of them. If the callback returns `false` for all of the entries (meaning none of them + // was interesting/useful), then the APK file descriptor is closed. Otherwise, the descriptor is + // kept open since we will need it later on. + static void scan_archive (const char *apk_path, ScanCallbackFn entry_cb) noexcept; + + private: + static std::tuple get_assemblies_prefix_and_length () noexcept; + + // Returns `true` if the APK fd needs to remain open. + static bool zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn entry_cb) noexcept; + static bool zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; + static bool zip_read_entry_info (std::vector const& buf, dynamic_local_string& file_name, zip_scan_state &state) noexcept; + static bool zip_load_entry_common (size_t entry_index, std::vector const& buf, dynamic_local_string &entry_name, zip_scan_state &state) noexcept; + static bool zip_adjust_data_offset (int fd, zip_scan_state &state) noexcept; + + template + static bool zip_extract_cd_info (std::array const& buf, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; + + template + static bool zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept; + + template + static bool zip_read_field (T const& src, size_t source_index, uint16_t& dst) noexcept; + + template + static bool zip_read_field (T const& src, size_t source_index, uint32_t& dst) noexcept; + + template + static bool zip_read_field (T const& src, size_t source_index, std::array& dst_sig) noexcept; + + template + static bool zip_read_field (T const& buf, size_t index, size_t count, dynamic_local_string& characters) noexcept; }; } diff --git a/src/native/clr/runtime-base/CMakeLists.txt b/src/native/clr/runtime-base/CMakeLists.txt index dbe6c2e634d..6a78f7022fc 100644 --- a/src/native/clr/runtime-base/CMakeLists.txt +++ b/src/native/clr/runtime-base/CMakeLists.txt @@ -3,6 +3,7 @@ set(LIB_ALIAS xa::runtime-base) set(XA_RUNTIME_BASE_SOURCES android-system.cc + cpu-arch-detect.cc logger.cc timing.cc timing-internal.cc diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index 7946cc30580..bc4f4e6ef25 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -140,6 +141,80 @@ AndroidSystem::setup_environment_from_override_file (dynamic_local_string 0, "At least a single application lib directory must be added"); + app_lib_directories = app_lib_directories.subspan (0, number_of_added_directories); +} + +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"sv); + + app_lib_directories = std::span (single_app_lib_directory); + app_lib_directories [0] = std::string (appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: {}", app_lib_directories [0]); + return; + } + + log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); + 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 = runtimeApks.get_length (); + AndroidSystem::app_lib_directories = std::span (new std::string[app_lib_directories_size], app_lib_directories_size); + } + + uint16_t built_for_cpu = 0, running_on_cpu = 0; + bool is64bit = false; + _monodroid_detect_cpu_and_architecture (built_for_cpu, running_on_cpu, is64bit); + setup_apk_directories (running_on_cpu, runtimeApks, have_split_apks); +} + void AndroidSystem::setup_environment () noexcept { diff --git a/src/native/clr/startup/zip.cc b/src/native/clr/startup/zip.cc index cef57b26618..add0c8b3dfc 100644 --- a/src/native/clr/startup/zip.cc +++ b/src/native/clr/startup/zip.cc @@ -1,3 +1,480 @@ +#include + +#include +#include +#include +#include + +#include +#include #include +#include using namespace xamarin::android; + +[[gnu::always_inline]] +std::tuple Zip::get_assemblies_prefix_and_length () noexcept +{ + return {lib_prefix.data (), lib_prefix.size () }; +} + +[[gnu::always_inline]] +bool Zip::zip_adjust_data_offset (int fd, zip_scan_state &state) noexcept +{ + static constexpr size_t LH_FILE_NAME_LENGTH_OFFSET = 26uz; + static constexpr size_t LH_EXTRA_LENGTH_OFFSET = 28uz; + + off_t result = ::lseek (fd, static_cast(state.local_header_offset), SEEK_SET); + if (result < 0) { + log_error ( + LOG_ASSEMBLY, + "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", + state.local_header_offset, std::strerror (errno), result, errno + ); + return false; + } + + std::array local_header; + std::array signature; + + ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); + if (nread < 0 || nread != ZIP_LOCAL_LEN) { + log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); + return false; + } + + size_t index = 0; + if (!zip_read_field (local_header, index, signature)) { + log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); + return false; + } + + if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { + log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); + return false; + } + + uint16_t file_name_length; + index = LH_FILE_NAME_LENGTH_OFFSET; + if (!zip_read_field (local_header, index, file_name_length)) { + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); + return false; + } + + uint16_t extra_field_length; + index = LH_EXTRA_LENGTH_OFFSET; + if (!zip_read_field (local_header, index, extra_field_length)) { + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); + return false; + } + + state.data_offset = static_cast(state.local_header_offset) + file_name_length + extra_field_length + local_header.size (); + + return true; +} + +[[gnu::always_inline]] +bool Zip::zip_read_entry_info (std::vector const& buf, dynamic_local_string& file_name, zip_scan_state &state) noexcept +{ + constexpr size_t CD_COMPRESSION_METHOD_OFFSET = 10uz; + constexpr size_t CD_UNCOMPRESSED_SIZE_OFFSET = 24uz; + constexpr size_t CD_FILENAME_LENGTH_OFFSET = 28uz; + constexpr size_t CD_EXTRA_LENGTH_OFFSET = 30uz; + constexpr size_t CD_LOCAL_HEADER_POS_OFFSET = 42uz; + constexpr size_t CD_COMMENT_LENGTH_OFFSET = 32uz; + + size_t index = state.buf_offset; + zip_ensure_valid_params (buf, index, ZIP_CENTRAL_LEN); + + std::array signature; + if (!zip_read_field (buf, index, signature)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry signature"sv); + return false; + } + + if (memcmp (signature.data (), ZIP_CENTRAL_MAGIC.data (), signature.size ()) != 0) { + log_error (LOG_ASSEMBLY, "Invalid Central Directory entry signature"sv); + return false; + } + + index = state.buf_offset + CD_COMPRESSION_METHOD_OFFSET; + if (!zip_read_field (buf, index, state.compression_method)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'compression method' field"sv); + return false; + } + + index = state.buf_offset + CD_UNCOMPRESSED_SIZE_OFFSET;; + if (!zip_read_field (buf, index, state.file_size)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'uncompressed size' field"sv); + return false; + } + + uint16_t file_name_length; + index = state.buf_offset + CD_FILENAME_LENGTH_OFFSET; + if (!zip_read_field (buf, index, file_name_length)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'file name length' field"sv); + return false; + } + + uint16_t extra_field_length; + index = state.buf_offset + CD_EXTRA_LENGTH_OFFSET; + if (!zip_read_field (buf, index, extra_field_length)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'extra field length' field"sv); + return false; + } + + uint16_t comment_length; + index = state.buf_offset + CD_COMMENT_LENGTH_OFFSET; + if (!zip_read_field (buf, index, comment_length)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'file comment length' field"sv); + return false; + } + + index = state.buf_offset + CD_LOCAL_HEADER_POS_OFFSET; + if (!zip_read_field (buf, index, state.local_header_offset)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'relative offset of local header' field"sv); + return false; + } + index += sizeof(state.local_header_offset); + + if (file_name_length == 0) { + file_name.clear (); + } else if (!zip_read_field (buf, index, file_name_length, file_name)) { + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'file name' field"sv); + return false; + } + + state.buf_offset += ZIP_CENTRAL_LEN + file_name_length + extra_field_length + comment_length; + return true; +} + +bool Zip::zip_load_entry_common (size_t entry_index, std::vector const& buf, dynamic_local_string &entry_name, zip_scan_state &state) noexcept +{ + entry_name.clear (); + + bool result = zip_read_entry_info (buf, entry_name, state); + + log_debug (LOG_ASSEMBLY, "{} entry: {}", optional_string (state.file_name), optional_string (entry_name.get (), "unknown")); + if (!result || entry_name.empty ()) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Failed to read Central Directory info for entry {} in APK {}", + entry_index, + optional_string (state.file_name) + ) + ); + } + + if (!zip_adjust_data_offset (state.file_fd, state)) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Failed to adjust data start offset for entry {} in APK {}", + entry_index, + optional_string (state.file_name) + ) + ); + } + + log_debug (LOG_ASSEMBLY, " ZIP: local header offset: {}; data offset: {}; file size: {}", state.local_header_offset, state.data_offset, state.file_size); + if (state.compression_method != 0) { + return false; + } + + if (entry_name.get ()[0] != state.prefix[0] || entry_name.length () < state.prefix_len || memcmp (state.prefix, entry_name.get (), state.prefix_len) != 0) { + // state.prefix and lib_prefix can point to the same location, see get_assemblies_prefix_and_length() + // In such instance we short-circuit and avoid a couple of comparisons below. + if (state.prefix == lib_prefix.data ()) { + return false; + } + + if (entry_name.get ()[0] != lib_prefix[0] || memcmp (lib_prefix.data (), entry_name.get (), lib_prefix.size () - 1) != 0) { + return false; + } + } + + // assemblies must be 16-byte or 4-byte aligned, or Bad Things happen + if (((state.data_offset & 0xf) != 0) || ((state.data_offset & 0x3) != 0)) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Assembly '{}' is at bad offset {} in the APK (not aligned to 4 or 16 bytes). 'zipalign' MUST be used on {} to align it properly", + optional_string (entry_name.get ()), + state.data_offset, + strrchr (state.file_name, '/') + 1 + ) + ); + } + + return true; +} + +template [[gnu::always_inline]] +bool Zip::zip_extract_cd_info (std::array const& buf, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept +{ + constexpr size_t EOCD_TOTAL_ENTRIES_OFFSET = 10uz; + constexpr size_t EOCD_CD_SIZE_OFFSET = 12uz; + constexpr size_t EOCD_CD_START_OFFSET = 16uz; + + static_assert (BufSize >= ZIP_EOCD_LEN, "Buffer too short for EOCD"); + + if (!zip_read_field (buf, EOCD_TOTAL_ENTRIES_OFFSET, cd_entries)) { + log_error (LOG_ASSEMBLY, "Failed to read EOCD 'total number of entries' field"sv); + return false; + } + + if (!zip_read_field (buf, EOCD_CD_START_OFFSET, cd_offset)) { + log_error (LOG_ASSEMBLY, "Failed to read EOCD 'central directory size' field"sv); + return false; + } + + if (!zip_read_field (buf, EOCD_CD_SIZE_OFFSET, cd_size)) { + log_error (LOG_ASSEMBLY, "Failed to read EOCD 'central directory offset' field"sv); + return false; + } + + return true; +} + +template [[gnu::always_inline]] +bool Zip::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept +{ + if (index + to_read > buf.size ()) { + log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); + return false; + } + + return true; +} + +template [[gnu::always_inline]] +bool Zip::zip_read_field (T const& src, size_t source_index, uint16_t& dst) noexcept +{ + if (!zip_ensure_valid_params (src, source_index, sizeof (dst))) { + return false; + } + + dst = static_cast((src [source_index + 1] << 8) | src [source_index]); + return true; +} + +template [[gnu::always_inline]] +bool Zip::zip_read_field (T const& src, size_t source_index, uint32_t& dst) noexcept +{ + if (!zip_ensure_valid_params (src, source_index, sizeof (dst))) { + return false; + } + + dst = + (static_cast (src [source_index + 3]) << 24) | + (static_cast (src [source_index + 2]) << 16) | + (static_cast (src [source_index + 1]) << 8) | + (static_cast (src [source_index + 0])); + + return true; +} + +template [[gnu::always_inline]] +bool Zip::zip_read_field (T const& src, size_t source_index, std::array& dst_sig) noexcept +{ + if (!zip_ensure_valid_params (src, source_index, dst_sig.size ())) { + return false; + } + + memcpy (dst_sig.data (), src.data () + source_index, dst_sig.size ()); + return true; +} + +template [[gnu::always_inline]] +bool Zip::zip_read_field (T const& buf, size_t index, size_t count, dynamic_local_string& characters) noexcept +{ + if (!zip_ensure_valid_params (buf, index, count)) { + return false; + } + + characters.assign (reinterpret_cast(buf.data () + index), count); + return true; +} + +[[gnu::always_inline]] +bool Zip::zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept +{ + // The simplest case - no file comment + off_t ret = ::lseek (apk_fd, -ZIP_EOCD_LEN, SEEK_END); + if (ret < 0) { + log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + return false; + } + + std::array eocd; + ssize_t nread = ::read (apk_fd, eocd.data (), eocd.size ()); + if (nread < 0 || nread != eocd.size ()) { + log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + return false; + } + + size_t index = 0uz; // signature + std::array signature; + + if (!zip_read_field (eocd, index, signature)) { + log_error (LOG_ASSEMBLY, "Failed to read EOCD signature"sv); + return false; + } + + if (memcmp (signature.data (), ZIP_EOCD_MAGIC.data (), signature.size ()) == 0) { + return zip_extract_cd_info (eocd, cd_offset, cd_size, cd_entries); + } + + // Most probably a ZIP with comment + constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed + ret = ::lseek (apk_fd, static_cast(-alloc_size), SEEK_END); + if (ret < 0) { + log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + return false; + } + + std::vector buf (alloc_size); + + nread = ::read (apk_fd, buf.data (), buf.size ()); + + if (nread < 0 || static_cast(nread) != alloc_size) { + log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + return false; + } + + // We scan from the end to save time + bool found = false; + const uint8_t* data = buf.data (); + for (ssize_t i = static_cast(alloc_size - (ZIP_EOCD_LEN + 2)); i >= 0z; i--) { + if (memcmp (data + i, ZIP_EOCD_MAGIC.data (), sizeof(ZIP_EOCD_MAGIC)) != 0) + continue; + + found = true; + memcpy (eocd.data (), data + i, ZIP_EOCD_LEN); + break; + } + + if (!found) { + log_error (LOG_ASSEMBLY, "Unable to find EOCD in the APK (with comment)"sv); + return false; + } + + return zip_extract_cd_info (eocd, cd_offset, cd_size, cd_entries); +} + +[[gnu::always_inline]] +bool Zip::zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn entry_cb) noexcept +{ + uint32_t cd_offset; + uint32_t cd_size; + uint16_t cd_entries; + + if (!zip_read_cd_info (apk_fd, cd_offset, cd_size, cd_entries)) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Failed to read the EOCD record from APK file %s", + optional_string (apk_path) + ) + ); + } + + log_debug (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); + log_debug (LOG_ASSEMBLY, "Central directory size: {}", cd_size); + log_debug (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); + + off_t retval = ::lseek (apk_fd, static_cast(cd_offset), SEEK_SET); + if (retval < 0) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Failed to seek to central directory position in APK: {}. retval={} errno={}, File={}", + std::strerror (errno), + retval, + errno, + optional_string (apk_path) + ) + ); + } + + std::vector buf (cd_size); + const auto [prefix, prefix_len] = get_assemblies_prefix_and_length (); + zip_scan_state state { + .file_fd = apk_fd, + .file_name = apk_path, + .prefix = prefix, + .prefix_len = prefix_len, + .buf_offset = 0uz, + .compression_method = 0u, + .local_header_offset = 0u, + .data_offset = 0u, + .file_size = 0u, + .bundled_assemblies_slow_path = false, + .max_assembly_name_size = 0u, + .max_assembly_file_name_size = 0u, + }; + + ssize_t nread; + do { + nread = read (apk_fd, buf.data (), buf.size ()); + } while (nread < 0 && errno == EINTR); + + if (static_cast(nread) != cd_size) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Failed to read Central Directory from APK: {}. nread={} errno={} File={}", + std::strerror (errno), + nread, + errno, + optional_string (apk_path) + ) + ); + } + + dynamic_local_string entry_name; + bool keep_archive_open = false; + + for (size_t i = 0uz; i < cd_entries; i++) { + bool interesting_entry = zip_load_entry_common (i, buf, entry_name, state); + if (!interesting_entry) { + continue; + } + + keep_archive_open |= entry_cb (apk_path, apk_fd, entry_name, state.data_offset, state.file_size); + } + + return keep_archive_open; +} + +void Zip::scan_archive (const char *apk_path, ScanCallbackFn entry_cb) noexcept +{ + int fd; + do { + fd = open (apk_path, O_RDONLY); + } while (fd < 0 && errno == EINTR); + + if (fd < 0) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "ERROR: Unable to load application package {}. {}", + optional_string (apk_path), strerror (errno) + ) + ); + } + log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk_path), fd); + if (!zip_scan_entries (fd, apk_path, entry_cb)) { + return; + } + + if (close (fd) < 0) { + log_warn ( + LOG_ASSEMBLY, + "Failed to close file descriptor for {}. {}", + optional_string (apk_path), + strerror (errno) + ); + } +} From d373f92d962e3df2cf58b0a7954bf82f06551b43 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 30 Jan 2025 20:48:24 +0100 Subject: [PATCH 086/143] Assembly stores support for CLR done --- src/native/CMakeLists.txt | 16 +- src/native/clr/host/CMakeLists.txt | 2 + src/native/clr/host/assembly-store.cc | 238 ++++++++++++++++++ src/native/clr/host/host.cc | 52 +++- src/native/clr/include/constants.hh | 14 +- src/native/clr/include/host/assembly-store.hh | 35 +++ src/native/clr/include/host/host.hh | 3 + .../include/runtime-base/android-system.hh | 12 +- src/native/clr/include/runtime-base/search.hh | 60 +++++ src/native/clr/include/runtime-base/util.hh | 102 +++++++- src/native/clr/include/shared/xxhash.hh | 2 + src/native/clr/include/startup/zip.hh | 48 ++-- src/native/clr/runtime-base/CMakeLists.txt | 54 ++++ src/native/clr/runtime-base/android-system.cc | 2 +- src/native/clr/startup/zip.cc | 34 ++- 15 files changed, 622 insertions(+), 52 deletions(-) create mode 100644 src/native/clr/host/assembly-store.cc create mode 100644 src/native/clr/include/host/assembly-store.hh create mode 100644 src/native/clr/include/runtime-base/search.hh diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index fe0c17d9607..a72c5672b3a 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -565,16 +565,16 @@ else() add_subdirectory(${SOURCES_PREFIX}/xamarin-app-stub) if (IS_MONO_RUNTIME) - add_subdirectory(mono/tracing) - add_subdirectory(mono/pinvoke-override) + add_subdirectory(mono/tracing) + add_subdirectory(mono/pinvoke-override) - if(DEBUG_BUILD) + if(DEBUG_BUILD) add_subdirectory(mono/xamarin-debug-app-helper) - endif() + endif() - add_subdirectory(mono/monodroid) + add_subdirectory(mono/monodroid) - add_custom_target(run_static_analysis + 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}" @@ -583,7 +583,7 @@ else() endif() if (IS_CLR_RUNTIME) - add_subdirectory(clr/host) - add_subdirectory(clr/startup) + add_subdirectory(clr/host) + add_subdirectory(clr/startup) endif() endif() diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index 9a0e1ad7b72..f0902043894 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -28,6 +28,7 @@ set(XAMARIN_NET_ANDROID_LIB "net-android${CHECKED_BUILD_INFIX}.${XAMARIN_NET_AND set(XAMARIN_NET_ANDROID_STATIC_LIB "${XAMARIN_NET_ANDROID_LIB}-static") set(XAMARIN_MONODROID_SOURCES + assembly-store.cc host.cc host-jni.cc ) @@ -130,6 +131,7 @@ macro(lib_target_options TARGET_NAME) ${TARGET_NAME} xa::xamarin-app ${SHARED_LIB_NAME} + xa::xamarin-startup xa::runtime-base xa::java-interop # xa::pinvoke-override-precompiled diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc new file mode 100644 index 00000000000..0e7c174b4c0 --- /dev/null +++ b/src/native/clr/host/assembly-store.cc @@ -0,0 +1,238 @@ +#include + +#if defined (HAVE_LZ4) +#include +#endif + +#include +#include +#include +#include +#include + +using namespace xamarin::android; + +[[gnu::always_inline]] +void AssemblyStore::set_assembly_data_and_size (uint8_t* source_assembly_data, uint32_t source_assembly_data_size, uint8_t*& dest_assembly_data, uint32_t& dest_assembly_data_size) noexcept +{ + dest_assembly_data = source_assembly_data; + dest_assembly_data_size = source_assembly_data_size; +} + +[[gnu::always_inline]] +auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name) noexcept -> std::tuple +{ + uint8_t *assembly_data = nullptr; + uint32_t assembly_data_size = 0; + +#if defined (HAVE_LZ4) && defined (RELEASE) + auto header = reinterpret_cast(e.image_data); + if (header->magic == COMPRESSED_DATA_MAGIC) { + if (compressed_assemblies.descriptors == nullptr) [[unlikely]] { + Helpers::abort_application (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined"sv); + } + if (header->descriptor_index >= compressed_assemblies.count) [[unlikely]] { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Invalid compressed assembly descriptor index {}", + header->descriptor_index + ) + ); + } + + CompressedAssemblyDescriptor &cad = compressed_assemblies.descriptors[header->descriptor_index]; + assembly_data_size = e.descriptor->data_size - sizeof(CompressedAssemblyHeader); + if (!cad.loaded) { + StartupAwareLock decompress_lock (assembly_decompress_mutex); + + if (cad.loaded) { + set_assembly_data_and_size (reinterpret_cast(cad.data), cad.uncompressed_file_size, assembly_data, assembly_data_size); + return {assembly_data, assembly_data_size}; + } + + if (cad.data == nullptr) [[unlikely]] { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Invalid compressed assembly descriptor at {}: no data", + header->descriptor_index + ) + ); + } + + if (header->uncompressed_length != cad.uncompressed_file_size) { + if (header->uncompressed_length > cad.uncompressed_file_size) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!", + name, + cad.uncompressed_file_size, + header->uncompressed_length + ) + ); + } else { + log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", name); + } + cad.uncompressed_file_size = header->uncompressed_length; + } + + const char *data_start = pointer_add(e.image_data, sizeof(CompressedAssemblyHeader)); + int ret = LZ4_decompress_safe (data_start, reinterpret_cast(cad.data), static_cast(assembly_data_size), static_cast(cad.uncompressed_file_size)); + + if (ret < 0) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Decompression of assembly {} failed with code {}", + name, + ret + ) + ); + } + + if (static_cast(ret) != cad.uncompressed_file_size) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Decompression of assembly {} yielded a different size (expected {}, got {})", + name, + cad.uncompressed_file_size, + static_cast(ret) + ) + ); + } + cad.loaded = true; + } + + set_assembly_data_and_size (reinterpret_cast(cad.data), cad.uncompressed_file_size, assembly_data, assembly_data_size); + } else +#endif // def HAVE_LZ4 && def RELEASE + { + set_assembly_data_and_size (e.image_data, e.descriptor->data_size, assembly_data, assembly_data_size); + } + + return {assembly_data, assembly_data_size}; +} + +[[gnu::always_inline]] +auto AssemblyStore::find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept -> const AssemblyStoreIndexEntry* +{ + auto equal = [](AssemblyStoreIndexEntry const& entry, hash_t key) -> bool { return entry.name_hash == key; }; + auto less_than = [](AssemblyStoreIndexEntry const& entry, hash_t key) -> bool { return entry.name_hash < key; }; + ssize_t idx = Search::binary_search (hash, entries, entry_count); + if (idx >= 0) { + return &entries[idx]; + } + return nullptr; +} + +auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) noexcept -> void* +{ + hash_t name_hash = xxhash::hash (name.data (), name.length ()); + log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", optional_string (name.data ()), name_hash); + + const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); + if (hash_entry == nullptr) { + log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.data ()), name_hash); + return nullptr; + } + + if (hash_entry->descriptor_index >= assembly_store.assembly_count) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Invalid assembly descriptor index {}, exceeds the maximum value of {}", + hash_entry->descriptor_index, + assembly_store.assembly_count - 1 + ) + ); + } + + AssemblyStoreEntryDescriptor &store_entry = assembly_store.assemblies[hash_entry->descriptor_index]; + AssemblyStoreSingleAssemblyRuntimeData &assembly_runtime_info = assembly_store_bundled_assemblies[store_entry.mapping_index]; + + if (assembly_runtime_info.image_data == nullptr) { + // The assignments here don't need to be atomic, the value will always be the same, so even if two threads + // arrive here at the same time, nothing bad will happen. + assembly_runtime_info.image_data = assembly_store.data_start + store_entry.data_offset; + assembly_runtime_info.descriptor = &store_entry; + if (store_entry.debug_data_offset != 0) { + assembly_runtime_info.debug_info_data = assembly_store.data_start + store_entry.debug_data_offset; + } + + log_debug ( + LOG_ASSEMBLY, + "Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'", + static_cast(assembly_runtime_info.image_data), + static_cast(assembly_runtime_info.debug_info_data), + static_cast(assembly_runtime_info.config_data), + static_cast(assembly_runtime_info.descriptor), + assembly_runtime_info.descriptor->data_size, + assembly_runtime_info.descriptor->debug_data_size, + assembly_runtime_info.descriptor->config_data_size, + name + ); + } + + auto [assembly_data, assembly_data_size] = get_assembly_data (assembly_runtime_info, name); + size = assembly_data_size; + return assembly_data; +} + +void AssemblyStore::map (int fd, std::string_view const& apk_path, std::string_view const& store_path, uint32_t offset, uint32_t size) noexcept +{ + detail::mmap_info assembly_store_map = Util::mmap_file (fd, offset, size, store_path); + + auto [payload_start, payload_size] = Util::get_wrapper_dso_payload_pointer_and_size (assembly_store_map, store_path); + log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); + auto header = static_cast(payload_start); + + auto get_full_store_path = [&apk_path, &store_path]() -> std::string { + std::string full_store_path; + + if (!apk_path.empty ()) { + full_store_path.append (apk_path); + // store path will be relative, to the apk + full_store_path.append ("!/"sv); + full_store_path.append (store_path); + } else { + full_store_path.append (store_path); + } + + return full_store_path; + }; + + if (header->magic != ASSEMBLY_STORE_MAGIC) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Assembly store '{}' is not a valid .NET for Android assembly store file", + get_full_store_path () + ) + ); + } + + if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", + get_full_store_path (), + header->version, + ASSEMBLY_STORE_FORMAT_VERSION + ) + ); + } + + constexpr size_t header_size = sizeof(AssemblyStoreHeader); + + assembly_store.data_start = static_cast(payload_start); + assembly_store.assembly_count = header->entry_count; + assembly_store.index_entry_count = header->index_entry_count; + assembly_store.assemblies = reinterpret_cast(assembly_store.data_start + header_size + header->index_size); + assembly_store_hashes = reinterpret_cast(assembly_store.data_start + header_size); + + log_debug (LOG_ASSEMBLY, "Mapped assembly store {}", get_full_store_path ()); +} diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index c19214a95b7..ae28d2581b3 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -25,7 +26,16 @@ bool Host::clr_bundle_probe (const char *path, void **data_start, int64_t *size) return false; // TODO: abort instead? } - return false; + *data_start = AssemblyStore::open_assembly (path, *size); + log_debug ( + LOG_ASSEMBLY, + "Assembly data {}mapped ({:p}, {} bytes)", + *data_start == nullptr ? "not "sv : ""sv, + *data_start, + *size + ); + + return *data_start != nullptr && *size > 0; } const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept @@ -34,8 +44,48 @@ const void* Host::clr_pinvoke_override (const char *library_name, const char *en return nullptr; } +auto Host::zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size) -> bool +{ + log_debug (LOG_ASSEMBLY, "zip entry: {}", entry_name.get ()); + if (!found_assembly_store) { + found_assembly_store = Zip::assembly_store_file_path.compare (0, entry_name.length (), entry_name.get ()) == 0; + if (found_assembly_store) { + log_debug (LOG_ASSEMBLY, "Found assembly store in '{}': {}", apk_path, Zip::assembly_store_file_path); + AssemblyStore::map (apk_fd, apk_path, Zip::assembly_store_file_path, offset, size); + return false; // This will make the scanner keep the APK open + } + } + return false; +} + void Host::gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks) { + if (!AndroidSystem::is_embedded_dso_mode_enabled ()) { + Helpers::abort_application ("Filesystem mode not supported yet."); + } + + int64_t apk_count = static_cast(runtimeApks.get_length ()); + bool got_split_config_abi_apk = false; + + for (int64_t i = 0; i < apk_count; i++) { + std::string_view apk_file = runtimeApks [static_cast(i)].get_string_view (); + + if (have_split_apks) { + bool scan_apk = false; + + // With split configs we need to scan only the abi apk, because both the assembly stores and the runtime + // configuration blob are in `lib/{ARCH}`, which in turn lives in the split config APK + if (!got_split_config_abi_apk && apk_file.ends_with (Constants::split_config_abi_apk_name.data ())) { + got_split_config_abi_apk = scan_apk = true; + } + + if (!scan_apk) { + continue; + } + } + + Zip::scan_archive (apk_file, zip_scan_callback); + } } void Host::create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept diff --git a/src/native/clr/include/constants.hh b/src/native/clr/include/constants.hh index f024da0a6eb..122e523aba0 100644 --- a/src/native/clr/include/constants.hh +++ b/src/native/clr/include/constants.hh @@ -17,12 +17,18 @@ namespace xamarin::android { #endif public: +#if INTPTR_MAX == INT64_MAX + static inline constexpr bool is_64_bit_target = true; +#else + static inline constexpr bool is_64_bit_target = false; +#endif + #if defined(RELEASE) - static constexpr bool IsReleaseBuild = true; - static constexpr bool IsDebugBuild = false; + static constexpr bool is_release_build = true; + static constexpr bool is_debug_build = false; #else - static constexpr bool IsReleaseBuild = false; - static constexpr bool IsDebugBuild = true; + static constexpr bool is_release_build = false; + static constexpr bool is_debug_build = true; #endif static constexpr std::string_view MANGLED_ASSEMBLY_NAME_EXT { ".so" }; diff --git a/src/native/clr/include/host/assembly-store.hh b/src/native/clr/include/host/assembly-store.hh new file mode 100644 index 00000000000..033e7d3ce1c --- /dev/null +++ b/src/native/clr/include/host/assembly-store.hh @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace xamarin::android { + class AssemblyStore + { + public: + static auto open_assembly (std::string_view const& name, int64_t &size) noexcept -> void*; + + static void map (int fd, std::string_view const& apk_path, std::string_view const& store_path, uint32_t offset, uint32_t size) noexcept; + + static void map (int fd, std::string_view const& file_path, uint32_t offset, uint32_t size) noexcept + { + map (fd, {}, file_path, offset, size); + } + + private: + static void set_assembly_data_and_size (uint8_t* source_assembly_data, uint32_t source_assembly_data_size, uint8_t*& dest_assembly_data, uint32_t& dest_assembly_data_size) noexcept; + + // Returns a tuple of + static auto get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name) noexcept -> std::tuple; + static auto find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept -> const AssemblyStoreIndexEntry*; + + private: + static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; + static inline std::mutex assembly_decompress_mutex {}; + }; +} diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index a1489671009..daff14a83ec 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -26,6 +26,7 @@ namespace xamarin::android { private: static void create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept; static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept; + static auto zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size) -> bool; static void gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks); static size_t clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept; @@ -36,12 +37,14 @@ namespace xamarin::android { static inline void *clr_host = nullptr; static inline unsigned int domain_id = 0; static inline std::unique_ptr _timing{}; + static inline bool found_assembly_store = false; static inline host_runtime_contract runtime_contract{ .size = sizeof(host_runtime_contract), .context = nullptr, .get_runtime_property = clr_get_runtime_property, .android_bundle_probe = clr_bundle_probe, + .bundle_probe = nullptr, .pinvoke_override = clr_pinvoke_override, }; }; diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index 3e9546e0dcf..28e87b322e2 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -60,7 +60,7 @@ namespace xamarin::android { static void create_update_dir (std::string const& override_dir) noexcept { - if constexpr (Constants::IsReleaseBuild) { + if constexpr (Constants::is_release_build) { /* * Don't create .__override__ on Release builds, because Google requires * that pre-loaded apps not create world-writable directories. @@ -78,6 +78,11 @@ namespace xamarin::android { log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); } + static auto is_embedded_dso_mode_enabled () noexcept -> bool + { + return embedded_dso_mode_enabled; + } + static auto monodroid_get_system_property (std::string_view const& name, dynamic_local_string &value) noexcept -> int; static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; static void setup_environment () noexcept; @@ -100,11 +105,6 @@ namespace xamarin::android { embedded_dso_mode_enabled = yesno; } - static auto is_embedded_dso_mode_enabled () noexcept -> bool - { - return embedded_dso_mode_enabled; - } - static auto determine_primary_override_dir (jstring_wrapper &home) noexcept -> std::string { dynamic_local_string name { home.get_cstr () }; diff --git a/src/native/clr/include/runtime-base/search.hh b/src/native/clr/include/runtime-base/search.hh new file mode 100644 index 00000000000..8153759f841 --- /dev/null +++ b/src/native/clr/include/runtime-base/search.hh @@ -0,0 +1,60 @@ +// Dear Emacs, this is a -*- C++ -*- header +#pragma once + +#include + +#include "../shared/xxhash.hh" + +namespace xamarin::android { + class Search final + { + public: + template + [[gnu::always_inline]] + static ssize_t binary_search (hash_t key, const T *arr, size_t n) noexcept + { + static_assert (equal != nullptr, "equal is a required template parameter"); + static_assert (less_than != nullptr, "less_than is a required template parameter"); + + ssize_t left = -1z; + ssize_t right = static_cast(n); + + while (right - left > 1) { + ssize_t middle = (left + right) >> 1u; + if (less_than (arr[middle], key)) { + left = middle; + } else { + right = middle; + } + } + + return equal (arr[right], key) ? right : -1z; + } + + [[gnu::always_inline]] + static ssize_t binary_search (hash_t key, const hash_t *arr, size_t n) noexcept + { + auto equal = [](hash_t const& entry, hash_t key) -> bool { return entry == key; }; + auto less_than = [](hash_t const& entry, hash_t key) -> bool { return entry < key; }; + + return binary_search (key, arr, n); + } + + [[gnu::always_inline]] + static ptrdiff_t binary_search_branchless (hash_t x, const hash_t *arr, uint32_t len) noexcept + { + const hash_t *base = arr; + while (len > 1) { + uint32_t half = len >> 1; + // __builtin_prefetch(&base[(len - half) / 2]); + // __builtin_prefetch(&base[half + (len - half) / 2]); + base = (base[half] < x ? &base[half] : base); + len -= half; + } + + //return *(base + (*base < x)); + ptrdiff_t ret = (base + (*base < x)) - arr; + return arr[ret] == x ? ret : -1; + } + }; +} diff --git a/src/native/clr/include/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 555b81e8db2..2d87bbffa66 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -1,13 +1,18 @@ #pragma once +#include +#include +#include +#include + +#include #include #include #include -#include - #include "../constants.hh" #include "../shared/helpers.hh" +#include "archive-dso-stub-config.hh" #include "jni-wrappers.hh" #include "logger.hh" #include "strings.hh" @@ -26,6 +31,12 @@ namespace xamarin::android { std::derived_from, dynamic_local_storage> || std::derived_from, static_local_storage>; }; + + struct mmap_info + { + void *area; + size_t size; + }; } class Util @@ -73,8 +84,8 @@ namespace xamarin::android { { if (createDirectory) { int rv = create_directory (value.get_cstr (), mode); - if (rv < 0 && errno != EEXIST) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}' for environment variable '{}'. {}", value.get_string_view (), name, strerror (errno)); + if (rv < 0 && errno != EEXIST) { + log_warn (LOG_DEFAULT, "Failed to create directory '{}' for environment variable '{}'. {}", value.get_string_view (), name, strerror (errno)); } } set_environment_variable (name, value); @@ -85,6 +96,86 @@ namespace xamarin::android { set_environment_variable_for_directory (name, value, true, Constants::DEFAULT_DIRECTORY_MODE); } + static int monodroid_getpagesize () noexcept + { + return page_size; + } + + static detail::mmap_info mmap_file (int fd, uint32_t offset, size_t size, std::string_view const& filename) noexcept + { + detail::mmap_info file_info; + detail::mmap_info mmap_info; + + size_t pageSize = static_cast(Util::monodroid_getpagesize ()); + size_t offsetFromPage = offset % pageSize; + size_t offsetPage = offset - offsetFromPage; + size_t offsetSize = size + offsetFromPage; + + mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); + + if (mmap_info.area == MAP_FAILED) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Could not mmap APK fd {}: {}; File={}", + fd, + strerror (errno), + filename + ) + ); + } + + mmap_info.size = offsetSize; + file_info.area = pointer_add (mmap_info.area, offsetFromPage); + file_info.size = size; + + log_info ( + LOG_ASSEMBLY, + " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + mmap_info.area, + pointer_add (mmap_info.area, mmap_info.size), + mmap_info.size, + file_info.area, + pointer_add (file_info.area, file_info.size), + file_info.size, + fd, + filename + ); + + return file_info; + } + + [[gnu::always_inline]] + static std::tuple get_wrapper_dso_payload_pointer_and_size (detail::mmap_info const& map_info, std::string_view const& file_name) noexcept + { + using Elf_Header = std::conditional_t; + using Elf_SHeader = std::conditional_t; + + const void* const mapped_elf = map_info.area; + auto elf_bytes = static_cast(mapped_elf); + auto elf_header = reinterpret_cast(mapped_elf); + + if constexpr (Constants::is_debug_build) { + // In debug mode we might be dealing with plain data, without DSO wrapper + if (elf_header->e_ident[EI_MAG0] != ELFMAG0 || + elf_header->e_ident[EI_MAG1] != ELFMAG1 || + elf_header->e_ident[EI_MAG2] != ELFMAG2 || + elf_header->e_ident[EI_MAG3] != ELFMAG3) { + log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", file_name); + // Not an ELF image, just return what we mmapped before + return { map_info.area, map_info.size }; + } + } + + auto section_header = reinterpret_cast(elf_bytes + elf_header->e_shoff); + Elf_SHeader const& payload_hdr = section_header[ArchiveDSOStubConfig::PayloadSectionIndex]; + + return { + const_cast(reinterpret_cast (elf_bytes + ArchiveDSOStubConfig::PayloadSectionOffset)), + payload_hdr.sh_size + }; + } + private: // TODO: needs some work to accept mixed params of different accepted types template TBuffer, detail::PathComponentString ...TPart> @@ -119,5 +210,8 @@ namespace xamarin::android { { path_combine_common (buf, std::forward(parts)...); } + + private: + static inline int page_size = getpagesize (); }; } diff --git a/src/native/clr/include/shared/xxhash.hh b/src/native/clr/include/shared/xxhash.hh index b66c2ce309a..32365aceab0 100644 --- a/src/native/clr/include/shared/xxhash.hh +++ b/src/native/clr/include/shared/xxhash.hh @@ -1,5 +1,7 @@ #pragma once +#include + #if INTPTR_MAX == INT64_MAX #define XXH_NO_STREAM #define XXH_INLINE_ALL diff --git a/src/native/clr/include/startup/zip.hh b/src/native/clr/include/startup/zip.hh index d9cf64ed269..0c846f50eb8 100644 --- a/src/native/clr/include/startup/zip.hh +++ b/src/native/clr/include/startup/zip.hh @@ -23,22 +23,22 @@ namespace xamarin::android { { public: // Returns `true` if the entry was something we need. - using ScanCallbackFn = bool(const char *apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size); + using ScanCallbackFn = bool(std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size); struct zip_scan_state { - int file_fd; - const char * file_name; - const char * const prefix; - uint32_t prefix_len; - size_t buf_offset; - uint16_t compression_method; - uint32_t local_header_offset; - uint32_t data_offset; - uint32_t file_size; - bool bundled_assemblies_slow_path; - uint32_t max_assembly_name_size; - uint32_t max_assembly_file_name_size; + int file_fd; + std::string_view const& file_name; + const char * const prefix; + uint32_t prefix_len; + size_t buf_offset; + uint16_t compression_method; + uint32_t local_header_offset; + uint32_t data_offset; + uint32_t file_size; + bool bundled_assemblies_slow_path; + uint32_t max_assembly_name_size; + uint32_t max_assembly_file_name_size; }; private: @@ -59,18 +59,36 @@ namespace xamarin::android { // .data() must be used otherwise string_view length will include the trailing \0 in the array static constexpr std::string_view lib_prefix { lib_prefix_array.data () }; + static constexpr std::string_view dso_suffix { ".so" }; + + static constexpr std::string_view assembly_store_prefix { "libassemblies." }; + static constexpr std::string_view assembly_store_extension { ".blob" }; + + static constexpr size_t assembly_store_file_name_size = calc_size (assembly_store_prefix, Constants::android_lib_abi, assembly_store_extension, dso_suffix); + static constexpr auto assembly_store_file_name_array = concat_string_views (assembly_store_prefix, Constants::android_lib_abi, assembly_store_extension, dso_suffix); + + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assembly_store_file_name { assembly_store_file_name_array.data () }; + + static constexpr size_t assembly_store_file_path_size = calc_size(lib_prefix, assembly_store_file_name); + static constexpr auto assembly_store_file_path_array = concat_string_views (lib_prefix, assembly_store_file_name); + + public: + // .data() must be used otherwise string_view length will include the trailing \0 in the array + static constexpr std::string_view assembly_store_file_path { assembly_store_file_path_array.data () }; + public: // Scans the ZIP archive for any entries matching the `lib/{ARCH}/` prefix and calls `entry_cb` // for each of them. If the callback returns `false` for all of the entries (meaning none of them // was interesting/useful), then the APK file descriptor is closed. Otherwise, the descriptor is // kept open since we will need it later on. - static void scan_archive (const char *apk_path, ScanCallbackFn entry_cb) noexcept; + static void scan_archive (std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept; private: static std::tuple get_assemblies_prefix_and_length () noexcept; // Returns `true` if the APK fd needs to remain open. - static bool zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn entry_cb) noexcept; + static bool zip_scan_entries (int apk_fd, std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept; static bool zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; static bool zip_read_entry_info (std::vector const& buf, dynamic_local_string& file_name, zip_scan_state &state) noexcept; static bool zip_load_entry_common (size_t entry_index, std::vector const& buf, dynamic_local_string &entry_name, zip_scan_state &state) noexcept; diff --git a/src/native/clr/runtime-base/CMakeLists.txt b/src/native/clr/runtime-base/CMakeLists.txt index 6a78f7022fc..93f83fea5a7 100644 --- a/src/native/clr/runtime-base/CMakeLists.txt +++ b/src/native/clr/runtime-base/CMakeLists.txt @@ -1,3 +1,51 @@ +# First generate some code + +# +# Must be the same value as DSOWrapperGenerator.PayloadSectionAlignment in src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs +# +set(ARCHIVE_DSO_STUB_PAYLOAD_SECTION_ALIGNMENT 0x4000) + +file(COPY "${XA_ARCHIVE_STUB_OUTPUT_DIRECTORY}/${ARCHIVE_DSO_STUB_LIB_FILE_NAME}" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +set(ARCHIVE_DSO_STUB_LIB_PATH "${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_DSO_STUB_LIB_FILE_NAME}") + +# Emulate what we do when embedding something inside the ELF file +set(PAYLOAD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt) + +execute_process( + COMMAND ${CMAKE_OBJCOPY} --add-section payload=${PAYLOAD_PATH} ${ARCHIVE_DSO_STUB_LIB_PATH} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ECHO_ERROR_VARIABLE + COMMAND_ERROR_IS_FATAL ANY +) + +execute_process( + COMMAND ${CMAKE_OBJCOPY} --set-section-flags payload=readonly,data --set-section-alignment payload=${ARCHIVE_DSO_STUB_PAYLOAD_SECTION_ALIGNMENT} ${ARCHIVE_DSO_STUB_LIB_PATH} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ECHO_ERROR_VARIABLE + COMMAND_ERROR_IS_FATAL ANY +) + +execute_process( + COMMAND ${CMAKE_READELF} --file-header --section-headers ${ARCHIVE_DSO_STUB_LIB_PATH} --elf-output-style=JSON + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + OUTPUT_VARIABLE ARCHIVE_DSO_STUB_HEADER_JSON + ECHO_ERROR_VARIABLE + COMMAND_ERROR_IS_FATAL ANY +) +string(JSON SECTION_HEADER_ENTRY_SIZE GET "${ARCHIVE_DSO_STUB_HEADER_JSON}" 0 "ElfHeader" "SectionHeaderEntrySize") +string(JSON SECTION_HEADER_ENTRY_COUNT GET "${ARCHIVE_DSO_STUB_HEADER_JSON}" 0 "ElfHeader" "SectionHeaderCount") + +math(EXPR PAYLOAD_SECTION_INDEX "${SECTION_HEADER_ENTRY_COUNT} - 1") +string(JSON PAYLOAD_SECTION_OFFSET GET "${ARCHIVE_DSO_STUB_HEADER_JSON}" 0 "Sections" ${PAYLOAD_SECTION_INDEX} "Section" "Offset") +file(REMOVE ${ARCHIVE_DSO_STUB_LIB_PATH}) + +message(STATUS "Archive DSO stub header entry size: ${SECTION_HEADER_ENTRY_SIZE}; section count: ${SECTION_HEADER_ENTRY_COUNT}; payload offset: ${PAYLOAD_SECTION_OFFSET}") +configure_file( + archive-dso-stub-config.hh.in + ${CMAKE_CURRENT_BINARY_DIR}/include/archive-dso-stub-config.hh + USE_SOURCE_PERMISSIONS +) + set(LIB_NAME runtime-base) set(LIB_ALIAS xa::runtime-base) @@ -35,6 +83,12 @@ target_compile_options( ${RUNTIME_BASE_CXX_ARGS} ) +target_include_directories( + ${LIB_NAME} + PUBLIC + "$" +) + target_include_directories( ${LIB_NAME} SYSTEM PRIVATE diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index bc4f4e6ef25..b97651b733d 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -236,7 +236,7 @@ AndroidSystem::setup_environment () noexcept var_value = ""; } - if constexpr (Constants::IsDebugBuild) { + if constexpr (Constants::is_debug_build) { log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); } diff --git a/src/native/clr/startup/zip.cc b/src/native/clr/startup/zip.cc index add0c8b3dfc..0c5413fb2d6 100644 --- a/src/native/clr/startup/zip.cc +++ b/src/native/clr/startup/zip.cc @@ -154,14 +154,14 @@ bool Zip::zip_load_entry_common (size_t entry_index, std::vector const& bool result = zip_read_entry_info (buf, entry_name, state); - log_debug (LOG_ASSEMBLY, "{} entry: {}", optional_string (state.file_name), optional_string (entry_name.get (), "unknown")); + log_debug (LOG_ASSEMBLY, "{} entry: {}", state.file_name, optional_string (entry_name.get (), "unknown")); if (!result || entry_name.empty ()) { Helpers::abort_application ( LOG_ASSEMBLY, std::format ( "Failed to read Central Directory info for entry {} in APK {}", entry_index, - optional_string (state.file_name) + state.file_name ) ); } @@ -172,7 +172,7 @@ bool Zip::zip_load_entry_common (size_t entry_index, std::vector const& std::format ( "Failed to adjust data start offset for entry {} in APK {}", entry_index, - optional_string (state.file_name) + state.file_name ) ); } @@ -196,13 +196,21 @@ bool Zip::zip_load_entry_common (size_t entry_index, std::vector const& // assemblies must be 16-byte or 4-byte aligned, or Bad Things happen if (((state.data_offset & 0xf) != 0) || ((state.data_offset & 0x3) != 0)) { + std::string_view::size_type pos = state.file_name.find_last_of ('/'); + if (pos == state.file_name.npos) { + pos = 0; + } else { + pos++; + } + std::string_view const& name_no_path = state.file_name.substr (pos); + Helpers::abort_application ( LOG_ASSEMBLY, std::format ( "Assembly '{}' is at bad offset {} in the APK (not aligned to 4 or 16 bytes). 'zipalign' MUST be used on {} to align it properly", optional_string (entry_name.get ()), state.data_offset, - strrchr (state.file_name, '/') + 1 + name_no_path ) ); } @@ -364,7 +372,7 @@ bool Zip::zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, } [[gnu::always_inline]] -bool Zip::zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn entry_cb) noexcept +bool Zip::zip_scan_entries (int apk_fd, std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept { uint32_t cd_offset; uint32_t cd_size; @@ -375,7 +383,7 @@ bool Zip::zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn ent LOG_ASSEMBLY, std::format ( "Failed to read the EOCD record from APK file %s", - optional_string (apk_path) + apk_path ) ); } @@ -393,7 +401,7 @@ bool Zip::zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn ent std::strerror (errno), retval, errno, - optional_string (apk_path) + apk_path ) ); } @@ -428,7 +436,7 @@ bool Zip::zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn ent std::strerror (errno), nread, errno, - optional_string (apk_path) + apk_path ) ); } @@ -448,11 +456,11 @@ bool Zip::zip_scan_entries (int apk_fd, const char *apk_path, ScanCallbackFn ent return keep_archive_open; } -void Zip::scan_archive (const char *apk_path, ScanCallbackFn entry_cb) noexcept +void Zip::scan_archive (std::string_view const& apk_path, ScanCallbackFn entry_cb) noexcept { int fd; do { - fd = open (apk_path, O_RDONLY); + fd = open (apk_path.data (), O_RDONLY); } while (fd < 0 && errno == EINTR); if (fd < 0) { @@ -460,11 +468,11 @@ void Zip::scan_archive (const char *apk_path, ScanCallbackFn entry_cb) noexcept LOG_ASSEMBLY, std::format ( "ERROR: Unable to load application package {}. {}", - optional_string (apk_path), strerror (errno) + apk_path, strerror (errno) ) ); } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk_path), fd); + log_debug (LOG_ASSEMBLY, "APK {} FD: {}", apk_path, fd); if (!zip_scan_entries (fd, apk_path, entry_cb)) { return; } @@ -473,7 +481,7 @@ void Zip::scan_archive (const char *apk_path, ScanCallbackFn entry_cb) noexcept log_warn ( LOG_ASSEMBLY, "Failed to close file descriptor for {}. {}", - optional_string (apk_path), + apk_path, strerror (errno) ); } From 9dd56b63ce4ad576a10ebdc5f09b5e098dc27975 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 31 Jan 2025 12:40:59 +0100 Subject: [PATCH 087/143] On the road to first managed call --- src/native/clr/host/CMakeLists.txt | 2 + src/native/clr/host/host-util.cc | 19 ++++ src/native/clr/host/host.cc | 89 +++++++++++++++++-- src/native/clr/host/os-bridge.cc | 25 ++++++ src/native/clr/include/constants.hh | 18 ++++ src/native/clr/include/host/host-util.hh | 11 +++ src/native/clr/include/host/host.hh | 28 ++++++ src/native/clr/include/host/os-bridge.hh | 16 ++++ .../include/runtime-base/android-system.hh | 9 ++ 9 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 src/native/clr/host/host-util.cc create mode 100644 src/native/clr/host/os-bridge.cc create mode 100644 src/native/clr/include/host/host-util.hh create mode 100644 src/native/clr/include/host/os-bridge.hh diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index f0902043894..3fbf47698a2 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -31,6 +31,8 @@ set(XAMARIN_MONODROID_SOURCES assembly-store.cc host.cc host-jni.cc + host-util.cc + os-bridge.cc ) list(APPEND LOCAL_CLANG_CHECK_SOURCES diff --git a/src/native/clr/host/host-util.cc b/src/native/clr/host/host-util.cc new file mode 100644 index 00000000000..1a1e49d8e34 --- /dev/null +++ b/src/native/clr/host/host-util.cc @@ -0,0 +1,19 @@ +#include +#include + +using namespace xamarin::android; + +auto HostUtil::get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) noexcept -> jclass +{ + static constexpr char java_lang_class_sig[] = "Ljava/lang/Class;"; + + jfieldID fieldID = env->GetStaticFieldID (runtime, name, java_lang_class_sig); + if (fieldID == nullptr) + return nullptr; + + jobject field = env->GetStaticObjectField (runtime, fieldID); + if (field == nullptr) + return nullptr; + + return reinterpret_cast (make_gref ? OSBridge::lref_to_gref (env, field) : field); +} diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index ae28d2581b3..fae00e8d939 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -117,7 +119,7 @@ void Host::create_xdg_directories_and_environment (jstring_wrapper &homeDir) noe create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME); } -void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, +void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeClass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) { @@ -149,12 +151,12 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, js AndroidSystem::setup_environment (); jstring_array_wrapper runtimeApks (env, runtimeApksJava); - AndroidSystem::setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); + AndroidSystem::setup_app_library_directories (runtimeApks, applicationDirs, haveSplitApks); gather_assemblies_and_libraries (runtimeApks, haveSplitApks); log_write (LOG_DEFAULT, LogLevel::Info, "Calling CoreCLR initialization routine"); - android_coreclr_initialize ( + int hr = android_coreclr_initialize ( application_config.android_package_name, u"Xamarin.Android", &runtime_contract, @@ -162,8 +164,85 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, js &clr_host, &domain_id ); + log_debug (LOG_ASSEMBLY, "CoreCLR init result == {}; clr_host == {:p}; domain ID == {}", hr, clr_host, domain_id); + // TODO: make S_OK & friends known to us + // if (hr != S_OK) { + // } log_write (LOG_DEFAULT, LogLevel::Info, "CoreCLR initialization routine returned"); + abort_unless ( + clr_host != nullptr, + [&hr] { + return detail::_format_message ("Failure to initialize CoreCLR host instance. Returned result %d", hr); + } + ); + + struct JnienvInitializeArgs init = {}; + init.javaVm = jvm; + init.env = env; + init.logCategories = log_categories; + init.version = env->GetVersion (); + init.isRunningOnDesktop = false; + init.brokenExceptionTransitions = 0; + init.packageNamingPolicy = static_cast(application_config.package_naming_policy); + init.boundExceptionType = 0; // System + init.jniAddNativeMethodRegistrationAttributePresent = application_config.jni_add_native_method_registration_attribute_present ? 1 : 0; + init.jniRemappingInUse = application_config.jni_remapping_replacement_type_count > 0 || application_config.jni_remapping_replacement_method_index_entry_count > 0; + init.marshalMethodsEnabled = application_config.marshal_methods_enabled; + + // GC threshold is 90% of the max GREF count + init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); + init.grefClass = HostUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); + Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); + init.Class_forName = env->GetStaticMethodID (init.grefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); + + jclass lrefLoaderClass = env->GetObjectClass (loader); + init.Loader_loadClass = env->GetMethodID (lrefLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + env->DeleteLocalRef (lrefLoaderClass); + + init.grefLoader = env->NewGlobalRef (loader); + init.grefIGCUserPeer = HostUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true); + init.grefGCUserPeerable = HostUtil::get_class_from_runtime_field (env, runtimeClass, "net_dot_jni_GCUserPeerable", true); + + log_info (LOG_GC, "GREF GC Threshold: {}", init.grefGcThreshold); + + // TODO: GC bridge to initialize here + + OSBridge::initialize_on_runtime_init (env, runtimeClass); + + log_debug (LOG_DEFAULT, "Calling into managed runtime init"sv); + + size_t native_to_managed_index; + if (FastTiming::enabled ()) [[unlikely]] { + native_to_managed_index = internal_timing->start_event (TimingEventKind::NativeToManagedTransition); + } + + log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.Initialize", Constants::JNIENVINIT_FULL_TYPE_NAME); + void *delegate = nullptr; + hr = coreclr_create_delegate ( + clr_host, + domain_id, + Constants::MONO_ANDROID_ASSEMBLY_NAME.data (), + Constants::JNIENVINIT_FULL_TYPE_NAME.data (), + "Initialize", + &delegate + ); + log_debug (LOG_ASSEMBLY, "Delegate creation result == {}; delegate == {:p}", hr, delegate); + // TODO: make S_OK & friends known to us + // if (hr != S_OK) { + // } + + auto initialize = reinterpret_cast (delegate); + abort_unless ( + initialize != nullptr, + "Failed to obtain unmanaged-callers-only pointer to the Android.Runtime.JNIEnvInit.Initialize method." + ); + initialize (&init); + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing->end_event (native_to_managed_index); + } + if (FastTiming::enabled ()) [[unlikely]] { internal_timing->end_event (total_time_index); } @@ -171,8 +250,8 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, js auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint { - log_write (LOG_DEFAULT, LogLevel::Info, "Host init"); - + log_write (LOG_DEFAULT, LogLevel::Info, "Host OnLoad"); + jvm = vm; AndroidSystem::init_max_gref_count (); return JNI_VERSION_1_6; } diff --git a/src/native/clr/host/os-bridge.cc b/src/native/clr/host/os-bridge.cc new file mode 100644 index 00000000000..28b64be5744 --- /dev/null +++ b/src/native/clr/host/os-bridge.cc @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +using namespace xamarin::android; + +void OSBridge::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept +{ + abort_if_invalid_pointer_argument (env, "env"); + GCUserPeer_class = HostUtil::get_class_from_runtime_field(env, runtimeClass, "mono_android_GCUserPeer", true); + GCUserPeer_ctor = env->GetMethodID (GCUserPeer_class, "", "()V"); + abort_unless (GCUserPeer_class != nullptr && GCUserPeer_ctor != nullptr, "Failed to load mono.android.GCUserPeer!"); +} + +auto OSBridge::lref_to_gref (JNIEnv *env, jobject lref) noexcept -> jobject +{ + if (lref == 0) { + return 0; + } + + jobject g = env->NewGlobalRef (lref); + env->DeleteLocalRef (lref); + return g; +} diff --git a/src/native/clr/include/constants.hh b/src/native/clr/include/constants.hh index 122e523aba0..a0d1b42630d 100644 --- a/src/native/clr/include/constants.hh +++ b/src/native/clr/include/constants.hh @@ -91,7 +91,10 @@ namespace xamarin::android { static constexpr std::string_view split_config_prefix { "/split_config." }; static constexpr std::string_view split_config_extension { ".apk" }; + private: static constexpr size_t split_config_abi_apk_name_size = calc_size (split_config_prefix, android_abi, split_config_extension); + + public: static constexpr auto split_config_abi_apk_name = concat_string_views (split_config_prefix, android_abi, split_config_extension); // @@ -121,5 +124,20 @@ namespace xamarin::android { static constexpr std::string_view OVERRIDE_ENVIRONMENT_FILE_NAME { "environment" }; static constexpr uint32_t OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE = 22; #endif + + static constexpr std::string_view MONO_ANDROID_ASSEMBLY_NAME { "Mono.Android" }; + static constexpr std::string_view ANDROID_RUNTIME_NS_NAME { "Android.Runtime" }; + static constexpr std::string_view JNIENVINIT_CLASS_NAME { "JNIEnvInit" }; + static constexpr std::string_view JNIENV_CLASS_NAME { "JNIEnv" }; + + private: + static constexpr size_t JNIENVINIT_FULL_TYPE_NAME_SIZE = calc_size (ANDROID_RUNTIME_NS_NAME, "."sv, JNIENVINIT_CLASS_NAME); + static constexpr auto JNIENVINIT_FULL_TYPE_NAME_ARRAY = concat_string_views (ANDROID_RUNTIME_NS_NAME, "."sv, JNIENVINIT_CLASS_NAME); + + public: + static constexpr std::string_view JNIENVINIT_FULL_TYPE_NAME { JNIENVINIT_FULL_TYPE_NAME_ARRAY.data () }; + + static constexpr std::string_view ANDROID_ENVIRONMENT_CLASS_NAME { "AndroidEnvironment" }; + static constexpr std::string_view ANDROID_RUNTIME_INTERNAL_CLASS_NAME { "AndroidRuntimeInternal" }; }; } diff --git a/src/native/clr/include/host/host-util.hh b/src/native/clr/include/host/host-util.hh new file mode 100644 index 00000000000..8fb9edc0873 --- /dev/null +++ b/src/native/clr/include/host/host-util.hh @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace xamarin::android { + class HostUtil + { + public: + static auto get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) noexcept -> jclass; + }; +} diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index daff14a83ec..37351fa98df 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -10,8 +10,33 @@ #include "../shared/log_types.hh" namespace xamarin::android { + // NOTE: Keep this in sync with managed side in src/Mono.Android/Android.Runtime/JNIEnvInit.cs + struct JnienvInitializeArgs + { + JavaVM *javaVm; + JNIEnv *env; + jobject grefLoader; + jmethodID Loader_loadClass; + jclass grefClass; + jmethodID Class_forName; + unsigned int logCategories; + int version; + int grefGcThreshold; + jobject grefIGCUserPeer; + int isRunningOnDesktop; + uint8_t brokenExceptionTransitions; + int packageNamingPolicy; + uint8_t boundExceptionType; + int jniAddNativeMethodRegistrationAttributePresent; + bool jniRemappingInUse; + bool marshalMethodsEnabled; + jobject grefGCUserPeerable; + }; + class Host { + using jnienv_initialize_fn = void (*) (JnienvInitializeArgs*); + public: static auto Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint; static void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, @@ -39,6 +64,9 @@ namespace xamarin::android { static inline std::unique_ptr _timing{}; static inline bool found_assembly_store = false; + static inline JavaVM *jvm = nullptr; + static inline jmethodID Class_getName = nullptr; + static inline host_runtime_contract runtime_contract{ .size = sizeof(host_runtime_contract), .context = nullptr, diff --git a/src/native/clr/include/host/os-bridge.hh b/src/native/clr/include/host/os-bridge.hh new file mode 100644 index 00000000000..8634970d975 --- /dev/null +++ b/src/native/clr/include/host/os-bridge.hh @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace xamarin::android { + class OSBridge + { + public: + static void initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept; + static auto lref_to_gref (JNIEnv *env, jobject lref) noexcept -> jobject; + + private: + static inline jclass GCUserPeer_class = nullptr; + static inline jmethodID GCUserPeer_ctor = nullptr; + }; +} diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index 28e87b322e2..70675d10315 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -33,6 +34,14 @@ namespace xamarin::android { }; public: + static auto get_gref_gc_threshold () noexcept -> long + { + if (max_gref_count == std::numeric_limits::max ()) { + return max_gref_count; + } + return static_cast ((max_gref_count * 90LL) / 100LL); + } + static auto get_max_gref_count () noexcept -> long { return max_gref_count; From 1d03a762293b1aecb9c40b4f008092265e04d092 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 31 Jan 2025 19:22:44 +0100 Subject: [PATCH 088/143] Hook into some error logging in CLR --- CLR-Host-Notes.md | 1 + src/native/clr/host/host.cc | 12 +++++++++--- src/native/clr/include/host/host.hh | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CLR-Host-Notes.md b/CLR-Host-Notes.md index 535d98d59a6..d89f989716e 100644 --- a/CLR-Host-Notes.md +++ b/CLR-Host-Notes.md @@ -11,3 +11,4 @@ p/invoke names for instance, can be Unicode. So can be the assembly names. Native library names should be UTF-8, but we can generate lookup tables for those at application build time (e.g. indexed by an xxHash of the Unicode version of the name) - no conversion at run time. + * We need declarations of all he possible HRESULT errors (`S_OK` etc) diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index fae00e8d939..554cbd12055 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -15,6 +15,11 @@ using namespace xamarin::android; +void Host::clr_error_writer (const char *message) noexcept +{ + log_error (LOG_DEFAULT, "CLR error: {}", optional_string (message)); +} + size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept { log_info (LOG_DEFAULT, "clr_get_runtime_property (\"{}\"...)", key); @@ -156,6 +161,7 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl gather_assemblies_and_libraries (runtimeApks, haveSplitApks); log_write (LOG_DEFAULT, LogLevel::Info, "Calling CoreCLR initialization routine"); + coreclr_set_error_writer (clr_error_writer); int hr = android_coreclr_initialize ( application_config.android_package_name, u"Xamarin.Android", @@ -164,7 +170,7 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl &clr_host, &domain_id ); - log_debug (LOG_ASSEMBLY, "CoreCLR init result == {}; clr_host == {:p}; domain ID == {}", hr, clr_host, domain_id); + log_debug (LOG_ASSEMBLY, "CoreCLR init result == {:x}; clr_host == {:p}; domain ID == {}", static_cast(hr), clr_host, domain_id); // TODO: make S_OK & friends known to us // if (hr != S_OK) { // } @@ -173,7 +179,7 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl abort_unless ( clr_host != nullptr, [&hr] { - return detail::_format_message ("Failure to initialize CoreCLR host instance. Returned result %d", hr); + return detail::_format_message ("Failure to initialize CoreCLR host instance. Returned result 0x%x", static_cast(hr)); } ); @@ -227,7 +233,7 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl "Initialize", &delegate ); - log_debug (LOG_ASSEMBLY, "Delegate creation result == {}; delegate == {:p}", hr, delegate); + log_debug (LOG_ASSEMBLY, "Delegate creation result == {:x}; delegate == {:p}", static_cast(hr), delegate); // TODO: make S_OK & friends known to us // if (hr != S_OK) { // } diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 37351fa98df..c06b9a0f374 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -57,6 +57,7 @@ namespace xamarin::android { static size_t clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept; static bool clr_bundle_probe (const char *path, void **data_start, int64_t *size) noexcept; static const void* clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept; + static void clr_error_writer (const char *message) noexcept; private: static inline void *clr_host = nullptr; From ffe325d6ca6c37496c0e5c62a29df7d0ff546f40 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 3 Feb 2025 21:11:04 +0100 Subject: [PATCH 089/143] Package CoreCLR JIT library --- src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs | 1 + src/java-runtime/java/mono/android/clr/MonoPackageManager.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs index 2937f2eda3c..da12802fb40 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs @@ -40,6 +40,7 @@ public class MaybeUseLocalCLR : AndroidTask "libSystem.Native", "libSystem.Security.Cryptography.Native.Android", "libcoreclr", + "libclrjit", ]; static readonly string[] ClrLibraryExtensions = [ diff --git a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java index a589505aa6f..cb07e7fba04 100644 --- a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java @@ -89,7 +89,7 @@ public static void LoadApplication (Context context) ); Log.w ("XACLR", "MonoPackageManager.LoadApplication: call registerApplications"); - mono.android.app.ApplicationRegistration.registerApplications (); + net.dot.android.ApplicationRegistration.registerApplications (); Log.w ("XACLR", "MonoPackageManager.LoadApplication: initialized"); initialized = true; From aa8bee7ee71625e2b8cbb0034227afb9af7fbf0e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 4 Feb 2025 12:45:03 +0100 Subject: [PATCH 090/143] CoreCLR android runtime packs are available now. Adjust. --- ...oft.Android.Sdk.AssemblyResolution.targets | 8 +- .../Tasks/MaybeUseLocalClr.cs | 110 ++++++++---------- 2 files changed, 54 insertions(+), 64 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 a02dfa44f9f..2b486b06a2b 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 @@ -129,13 +129,13 @@ _ResolveAssemblies MSBuild target. LocalClrDirectory="$(_LocalClrDirectory)" ResolvedFilesToPublish="@(ResolvedFileToPublish)" AndroidRuntime="$(_AndroidRuntime)"> - - + + - - + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs index da12802fb40..b84e7aac64c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs @@ -16,39 +16,6 @@ namespace Xamarin.Android.Tasks; // public class MaybeUseLocalCLR : AndroidTask { - // - // Lists of items below must together create a full CoreCLR - // runtime pack. All components must be listed. This is just - // a temporary measure until there exist CoreCLR packs. - // When we have the packs, we will simply make sure that all the - // required CoreCLR pack items found in ResolvedFilesToPublish are - // also in our local directory. - // - - // Full file names, no path. - static readonly string[] RequiredClrComponents = [ - "System.Private.CoreLib.dll", - "libSystem.Security.Cryptography.Native.Android.dex", - "libSystem.Security.Cryptography.Native.Android.jar", - ]; - - // Just stems, without extension. Extensions we'll check for are: - static readonly string[] RequiredClrLibraries = [ - "libSystem.IO.Compression.Native", - "libSystem.Globalization.Native", - "libSystem.IO.Ports.Native", - "libSystem.Native", - "libSystem.Security.Cryptography.Native.Android", - "libcoreclr", - "libclrjit", - ]; - - static readonly string[] ClrLibraryExtensions = [ - ".so", - ".so.dbg", - ".a", - ]; - public override string TaskPrefix => "MULC"; public string LocalClrDirectory { get; set; } = String.Empty; @@ -60,10 +27,10 @@ public class MaybeUseLocalCLR : AndroidTask public string AndroidRuntime { get; set; } = String.Empty; [Output] - public ITaskItem[] SharedLibrariesToAdd { get; set; } + public ITaskItem[] ResolvedFilesToAdd { get; set; } [Output] - public ITaskItem[] SharedLibrariesToIgnore { get; set; } + public ITaskItem[] ResolvedFilesToIgnore { get; set; } public override bool RunTask () { @@ -83,28 +50,39 @@ public override bool RunTask () } var itemsToRemove = new List (); + var requiredClrItems = new List (); var supportedArchitectures = new HashSet (); foreach (ITaskItem lib in ResolvedFilesToPublish) { - ProcessItem (lib, itemsToRemove, supportedArchitectures); + ProcessItem (lib, itemsToRemove, requiredClrItems, supportedArchitectures); } var itemsToAdd = new List (); - foreach (string required in RequiredClrComponents) { + foreach (ITaskItem required in requiredClrItems) { MakeLocalPackItem (required, itemsToAdd, supportedArchitectures); } - foreach (string required in RequiredClrLibraries) { - foreach (string ext in ClrLibraryExtensions) { - MakeLocalPackItem ($"{required}{ext}", itemsToAdd, supportedArchitectures); - } + ResolvedFilesToAdd = itemsToAdd.ToArray (); + ResolvedFilesToIgnore = itemsToRemove.ToArray (); + return !Log.HasLoggedErrors; + } + + bool IsNativeAsset (ITaskItem item) + { + string? assetType = item.GetMetadata ("AssetType"); + if (String.IsNullOrEmpty (assetType)) { + return false; } - SharedLibrariesToAdd = itemsToAdd.ToArray (); - SharedLibrariesToIgnore = itemsToRemove.ToArray (); - return !Log.HasLoggedErrors; + // System.Private.CoreLib.dll is an exception - it has `AssetType` set to `runtime`, but it's actually in the `native` + // portion of the runtime pack. + if (String.Compare ("System.Private.CoreLib.dll", Path.GetFileName (item.ItemSpec), StringComparison.OrdinalIgnoreCase) == 0) { + return true; + } + + return String.Compare (assetType, "native", StringComparison.OrdinalIgnoreCase) == 0; } - void MakeLocalPackItem (string required, List itemsToAdd, HashSet supportedArchitectures) + void MakeLocalPackItem (ITaskItem required, List itemsToAdd, HashSet supportedArchitectures) { foreach (AndroidTargetArch arch in MonoAndroidHelper.SupportedTargetArchitectures) { if (!supportedArchitectures.Contains (arch)) { @@ -112,33 +90,35 @@ void MakeLocalPackItem (string required, List itemsToAdd, HashSet itemsToRemove, HashSet supportedArchitectures) + void ProcessItem (ITaskItem item, List itemsToRemove, List requiredClrItems, HashSet supportedArchitectures) { - if (LinuxBionicHack (item, itemsToRemove) || CoreClrItem (item, itemsToRemove)) { + if (LinuxBionicHack (item, itemsToRemove) || CoreClrItem (item, itemsToRemove, requiredClrItems)) { return; } @@ -150,16 +130,26 @@ void ProcessItem (ITaskItem item, List itemsToRemove, HashSet itemsToRemove) + bool CoreClrItem (ITaskItem item, List itemsToRemove, List requiredClrItems) { - // TODO: implement once CoreCLR runtime packs are available - return false; + string? nugetId = item.GetMetadata ("NuGetPackageId"); + if (String.IsNullOrEmpty (nugetId)) { + return false; + } + + const string BionicNugetIdPrefix = "Microsoft.NETCore.App.Runtime.android-"; + if (!nugetId.StartsWith (BionicNugetIdPrefix, StringComparison.OrdinalIgnoreCase)) { + return false; + } + + itemsToRemove.Add (item); + requiredClrItems.Add (item); + return true; } bool LinuxBionicHack (ITaskItem item, List itemsToRemove) { string? nugetId = item.GetMetadata ("NuGetPackageId"); - if (String.IsNullOrEmpty (nugetId)) { return false; } From 74147ef9a537424218114c9ab747f737137c1072 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 4 Feb 2025 18:50:21 +0100 Subject: [PATCH 091/143] Two special assemblies --- ...icrosoft.Android.Sdk.AssemblyResolution.targets | 14 ++++++++++++++ 1 file changed, 14 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 2b486b06a2b..e590d56e31e 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 @@ -65,6 +65,16 @@ _ResolveAssemblies MSBuild target. + + + + + + @@ -107,6 +117,10 @@ _ResolveAssemblies MSBuild target. <_ProjectToBuild Include="$(MSBuildProjectFile)" AdditionalProperties="RuntimeIdentifier=%(_RIDs.Identity);$(_AdditionalProperties)" /> + + + + Date: Tue, 4 Feb 2025 22:05:14 +0100 Subject: [PATCH 092/143] p/invoke override support --- .../scripts/generate-pinvoke-tables.sh | 93 +- src/native/clr/host/CMakeLists.txt | 2 + .../clr/host/generate-pinvoke-tables.cc | 747 ++++++++++++ src/native/clr/host/host.cc | 6 - src/native/clr/host/internal-pinvokes.cc | 16 + src/native/clr/host/os-bridge.cc | 101 ++ src/native/clr/host/pinvoke-override.cc | 92 ++ src/native/clr/host/pinvoke-tables.include | 1006 +++++++++++++++++ src/native/clr/include/host/os-bridge.hh | 25 + .../clr/include/host/pinvoke-override.hh | 223 ++++ .../include/runtime-base/android-system.hh | 11 + .../include/runtime-base/internal-pinvokes.hh | 6 + .../clr/include/runtime-base/strings.hh | 7 + src/native/clr/include/runtime-base/util.hh | 9 + src/native/clr/runtime-base/android-system.cc | 88 ++ 15 files changed, 2395 insertions(+), 37 deletions(-) create mode 100644 src/native/clr/host/generate-pinvoke-tables.cc create mode 100644 src/native/clr/host/internal-pinvokes.cc create mode 100644 src/native/clr/host/pinvoke-override.cc create mode 100644 src/native/clr/host/pinvoke-tables.include create mode 100644 src/native/clr/include/host/pinvoke-override.hh create mode 100644 src/native/clr/include/runtime-base/internal-pinvokes.hh diff --git a/build-tools/scripts/generate-pinvoke-tables.sh b/build-tools/scripts/generate-pinvoke-tables.sh index 2b0f8083e37..5099cdea0b1 100755 --- a/build-tools/scripts/generate-pinvoke-tables.sh +++ b/build-tools/scripts/generate-pinvoke-tables.sh @@ -2,11 +2,14 @@ MY_DIR="$(dirname $0)" HOST="$(uname | tr A-Z a-z)" -NATIVE_DIR="${MY_DIR}/../../src/native/mono" -MONODROID_SOURCE_DIR="${NATIVE_DIR}/pinvoke-override" -GENERATOR_SOURCE="${MONODROID_SOURCE_DIR}/generate-pinvoke-tables.cc" -GENERATOR_BINARY="${MONODROID_SOURCE_DIR}/generate-pinvoke-tables" -TARGET_FILE="${MONODROID_SOURCE_DIR}/pinvoke-tables.include" +NATIVE_DIR="${MY_DIR}/../../src/native" +MONODROID_SOURCE_DIR="${NATIVE_DIR}/mono/pinvoke-override" +MONODROID_INCLUDE_DIR="${NATIVE_DIR}/mono/shared" +CLR_SOURCE_DIR="${NATIVE_DIR}/clr/host" +CLR_INCLUDE_DIR="${NATIVE_DIR}/clr/include/shared" +GENERATOR_SOURCE="generate-pinvoke-tables.cc" +GENERATOR_BINARY="generate-pinvoke-tables" +TARGET_FILE="pinvoke-tables.include" GENERATED_FILE="${TARGET_FILE}.generated" DIFF_FILE="${TARGET_FILE}.diff" EXTERNAL_DIR="${MY_DIR}/../../external/" @@ -64,33 +67,61 @@ case ${HOST} in *) die Unsupported OS ;; esac -${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 -I${NATIVE_DIR}/shared -I${NATIVE_DIR}/../common/include "${GENERATOR_SOURCE}" -o "${GENERATOR_BINARY}" -"${GENERATOR_BINARY}" "${GENERATED_FILE}" - -FILES_DIFFER="no" -cmp "${GENERATED_FILE}" "${TARGET_FILE}" > /dev/null 2>&1 || FILES_DIFFER="yes" - -RETVAL=0 -if [ "${TEST_ONLY}" == "no" ]; then - if [ "${FILES_DIFFER}" == "yes" ]; then - mv "${GENERATED_FILE}" "${TARGET_FILE}" - else - rm "${GENERATED_FILE}" - fi -else - if [ "${FILES_DIFFER}" == "yes" ]; then - echo "Generated p/invokes table file differs from the current one" - diff -U3 -Narp "${TARGET_FILE}" "${GENERATED_FILE}" > "${DIFF_FILE}" - - echo "Diff file saved in: ${DIFF_FILE}" - echo "------ DIFF START ------" - cat "${DIFF_FILE}" - echo "------ DIFF END ------" - echo - RETVAL=1 +function generate() +{ + local SOURCE_DIR="${1}" + local INCLUDE_DIR="${2}" + local SOURCE="${SOURCE_DIR}/${GENERATOR_SOURCE}" + local BINARY="${SOURCE_DIR}/${GENERATOR_BINARY}" + local RESULT="${SOURCE_DIR}/${GENERATED_FILE}" + local TARGET="${SOURCE_DIR}/${TARGET_FILE}" + local DIFF="${SOURCE_DIR}/${DIFF_FILE}" + + ${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 -I${INCLUDE_DIR} "${SOURCE}" -o "${BINARY}" + "${BINARY}" "${RESULT}" + + FILES_DIFFER="no" + cmp "${RESULT}" "${TARGET}" > /dev/null 2>&1 || FILES_DIFFER="yes" + + if [ "${TEST_ONLY}" == "no" ]; then + if [ "${FILES_DIFFER}" == "yes" ]; then + mv "${RESULT}" "${TARGET}" + else + rm "${RESULT}" + fi else - echo Generated file is identical to the current one + if [ "${FILES_DIFFER}" == "yes" ]; then + echo "Generated p/invokes table file differs from the current one" + diff -U3 -Narp "${TARGET}" "${RESULT}" > "${DIFF}" + + echo "Diff file saved in: ${DIFF}" + echo "------ DIFF START ------" + cat "${DIFF}" + echo "------ DIFF END ------" + echo + RETVAL=1 + else + echo Generated file is identical to the current one + fi fi -fi +} + +RETVAL=0 +cat < +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xxhash.hh" + +namespace fs = std::filesystem; +using namespace xamarin::android; + +const std::vector internal_pinvoke_names = { +// "create_public_directory", +// "java_interop_free", +// "monodroid_clear_gdb_wait", +// "_monodroid_counters_dump", +// "_monodroid_detect_cpu_and_architecture", +// "monodroid_dylib_mono_free", +// "monodroid_dylib_mono_init", +// "monodroid_dylib_mono_new", +// "monodroid_embedded_assemblies_set_assemblies_prefix", +// "monodroid_fopen", +// "monodroid_free", +// "_monodroid_freeifaddrs", +// "_monodroid_gc_wait_for_bridge_processing", +// "_monodroid_get_dns_servers", +// "monodroid_get_dylib", +// "_monodroid_getifaddrs", +// "monodroid_get_namespaced_system_property", +// "_monodroid_get_network_interface_supports_multicast", +// "_monodroid_get_network_interface_up_state", +// "monodroid_get_system_property", + "_monodroid_gref_get", +// "_monodroid_gref_log", +// "_monodroid_gref_log_delete", + "_monodroid_gref_log_new", +// "monodroid_log", +// "monodroid_log_traces", +// "_monodroid_lookup_replacement_type", +// "_monodroid_lookup_replacement_method_info", +// "_monodroid_lref_log_delete", +// "_monodroid_lref_log_new", +// "_monodroid_max_gref_get", +// "monodroid_strdup_printf", +// "monodroid_strfreev", +// "monodroid_strsplit", +// "_monodroid_timezone_get_default_id", +// "monodroid_timing_start", +// "monodroid_timing_stop", +// "monodroid_TypeManager_get_java_class_name", +// "_monodroid_weak_gref_delete", +// "_monodroid_weak_gref_get", +// "_monodroid_weak_gref_new", +// "path_combine", +// "recv_uninterrupted", +// "send_uninterrupted", +// "set_world_accessable", +}; + +const std::vector dotnet_pinvoke_names = { + // libSystem.Globalization.Native.so + "GlobalizationNative_ChangeCase", + "GlobalizationNative_ChangeCaseInvariant", + "GlobalizationNative_ChangeCaseTurkish", + "GlobalizationNative_CloseSortHandle", + "GlobalizationNative_CompareString", + "GlobalizationNative_EndsWith", + "GlobalizationNative_EnumCalendarInfo", + "GlobalizationNative_GetCalendarInfo", + "GlobalizationNative_GetCalendars", + "GlobalizationNative_GetDefaultLocaleName", + "GlobalizationNative_GetICUVersion", + "GlobalizationNative_GetJapaneseEraStartDate", + "GlobalizationNative_GetLatestJapaneseEra", + "GlobalizationNative_GetLocaleInfoGroupingSizes", + "GlobalizationNative_GetLocaleInfoInt", + "GlobalizationNative_GetLocaleInfoString", + "GlobalizationNative_GetLocaleName", + "GlobalizationNative_GetLocales", + "GlobalizationNative_GetLocaleTimeFormat", + "GlobalizationNative_GetSortHandle", + "GlobalizationNative_GetSortKey", + "GlobalizationNative_GetSortVersion", + "GlobalizationNative_GetTimeZoneDisplayName", + "GlobalizationNative_IanaIdToWindowsId", + "GlobalizationNative_IndexOf", + "GlobalizationNative_InitICUFunctions", + "GlobalizationNative_InitOrdinalCasingPage", + "GlobalizationNative_IsNormalized", + "GlobalizationNative_IsPredefinedLocale", + "GlobalizationNative_LastIndexOf", + "GlobalizationNative_LoadICU", + "GlobalizationNative_NormalizeString", + "GlobalizationNative_StartsWith", + "GlobalizationNative_ToAscii", + "GlobalizationNative_ToUnicode", + "GlobalizationNative_WindowsIdToIanaId", + + // libSystem.IO.Compression.Native.so + "BrotliDecoderCreateInstance", + "BrotliDecoderDecompress", + "BrotliDecoderDecompressStream", + "BrotliDecoderDestroyInstance", + "BrotliDecoderErrorString", + "BrotliDecoderGetErrorCode", + "BrotliDecoderHasMoreOutput", + "BrotliDecoderIsFinished", + "BrotliDecoderIsUsed", + "BrotliDecoderSetParameter", + "BrotliDecoderTakeOutput", + "BrotliDecoderVersion", + "BrotliDefaultAllocFunc", + "BrotliDefaultFreeFunc", + "BrotliEncoderCompress", + "BrotliEncoderCompressStream", + "BrotliEncoderCreateInstance", + "BrotliEncoderDestroyInstance", + "BrotliEncoderHasMoreOutput", + "BrotliEncoderIsFinished", + "BrotliEncoderMaxCompressedSize", + "BrotliEncoderSetParameter", + "BrotliEncoderTakeOutput", + "BrotliEncoderVersion", + "BrotliGetDictionary", + "BrotliGetTransforms", + "BrotliSetDictionaryData", + "BrotliTransformDictionaryWord", + "CompressionNative_Crc32", + "CompressionNative_Deflate", + "CompressionNative_DeflateEnd", + "CompressionNative_DeflateInit2_", + "CompressionNative_Inflate", + "CompressionNative_InflateEnd", + "CompressionNative_InflateInit2_", + + // libSystem.Native.so + "SystemNative_Abort", + "SystemNative_Accept", + "SystemNative_Access", + "SystemNative_AlignedAlloc", + "SystemNative_AlignedFree", + "SystemNative_AlignedRealloc", + "SystemNative_Bind", + "SystemNative_Calloc", + "SystemNative_CanGetHiddenFlag", + "SystemNative_ChDir", + "SystemNative_ChMod", + "SystemNative_Close", + "SystemNative_CloseDir", + "SystemNative_CloseSocketEventPort", + "SystemNative_ConfigureTerminalForChildProcess", + "SystemNative_Connect", + "SystemNative_Connectx", + "SystemNative_ConvertErrorPalToPlatform", + "SystemNative_ConvertErrorPlatformToPal", + "SystemNative_CopyFile", + "SystemNative_CreateAutoreleasePool", + "SystemNative_CreateNetworkChangeListenerSocket", + "SystemNative_CreateSocketEventBuffer", + "SystemNative_CreateSocketEventPort", + "SystemNative_CreateThread", + "SystemNative_DisablePosixSignalHandling", + "SystemNative_Disconnect", + "SystemNative_DrainAutoreleasePool", + "SystemNative_Dup", + "SystemNative_EnablePosixSignalHandling", + "SystemNative_EnumerateGatewayAddressesForInterface", + "SystemNative_EnumerateInterfaceAddresses", + "SystemNative_Exit", + "SystemNative_FAllocate", + "SystemNative_FChflags", + "SystemNative_FChMod", + "SystemNative_FcntlCanGetSetPipeSz", + "SystemNative_FcntlGetFD", + "SystemNative_FcntlGetIsNonBlocking", + "SystemNative_FcntlGetPipeSz", + "SystemNative_FcntlSetFD", + "SystemNative_FcntlSetIsNonBlocking", + "SystemNative_FcntlSetPipeSz", + "SystemNative_FLock", + "SystemNative_ForkAndExecProcess", + "SystemNative_Free", + "SystemNative_FreeEnviron", + "SystemNative_FreeHostEntry", + "SystemNative_FreeLibrary", + "SystemNative_FreeSocketEventBuffer", + "SystemNative_FStat", + "SystemNative_FSync", + "SystemNative_FTruncate", + "SystemNative_FUTimens", + "SystemNative_GetActiveTcpConnectionInfos", + "SystemNative_GetActiveUdpListeners", + "SystemNative_GetAddressFamily", + "SystemNative_GetAllMountPoints", + "SystemNative_GetAtOutOfBandMark", + "SystemNative_GetBootTimeTicks", + "SystemNative_GetBytesAvailable", + "SystemNative_GetControlCharacters", + "SystemNative_GetControlMessageBufferSize", + "SystemNative_GetCpuUtilization", + "SystemNative_GetCryptographicallySecureRandomBytes", + "SystemNative_GetCwd", + "SystemNative_GetDefaultSearchOrderPseudoHandle", + "SystemNative_GetDefaultTimeZone", + "SystemNative_GetDeviceIdentifiers", + "SystemNative_GetDomainName", + "SystemNative_GetDomainSocketSizes", + "SystemNative_GetEGid", + "SystemNative_GetEnv", + "SystemNative_GetEnviron", + "SystemNative_GetErrNo", + "SystemNative_GetEstimatedTcpConnectionCount", + "SystemNative_GetEstimatedUdpListenerCount", + "SystemNative_GetEUid", + "SystemNative_GetFileSystemType", + "SystemNative_GetFormatInfoForMountPoint", + "SystemNative_GetGroupList", + "SystemNative_GetGroupName", + "SystemNative_GetGroups", + "SystemNative_GetHostEntryForName", + "SystemNative_GetHostName", + "SystemNative_GetIcmpv4GlobalStatistics", + "SystemNative_GetIcmpv6GlobalStatistics", + "SystemNative_GetIPv4Address", + "SystemNative_GetIPv4GlobalStatistics", + "SystemNative_GetIPv4MulticastOption", + "SystemNative_GetIPv6Address", + "SystemNative_GetIPv6MulticastOption", + "SystemNative_GetLingerOption", + "SystemNative_GetLoadLibraryError", + "SystemNative_GetMaximumAddressSize", + "SystemNative_GetNameInfo", + "SystemNative_GetNativeIPInterfaceStatistics", + "SystemNative_GetNetworkInterfaces", + "SystemNative_GetNonCryptographicallySecureRandomBytes", + "SystemNative_GetNumRoutes", + "SystemNative_GetOSArchitecture", + "SystemNative_GetPeerID", + "SystemNative_GetPeerName", + "SystemNative_GetPid", + "SystemNative_GetPlatformSignalNumber", + "SystemNative_GetPort", + "SystemNative_GetPriority", + "SystemNative_GetProcAddress", + "SystemNative_GetProcessPath", + "SystemNative_GetPwNamR", + "SystemNative_GetPwUidR", + "SystemNative_GetRawSockOpt", + "SystemNative_GetReadDirRBufferSize", + "SystemNative_GetRLimit", + "SystemNative_GetSid", + "SystemNative_GetSignalForBreak", + "SystemNative_GetSocketAddressSizes", + "SystemNative_GetSocketErrorOption", + "SystemNative_GetSocketType", + "SystemNative_GetSockName", + "SystemNative_GetSockOpt", + "SystemNative_GetSpaceInfoForMountPoint", + "SystemNative_GetSystemTimeAsTicks", + "SystemNative_GetTcpGlobalStatistics", + "SystemNative_GetTimestamp", + "SystemNative_GetTimeZoneData", + "SystemNative_GetUdpGlobalStatistics", + "SystemNative_GetUInt64OSThreadId", + "SystemNative_GetUnixRelease", + "SystemNative_GetUnixVersion", + "SystemNative_GetWindowSize", + "SystemNative_HandleNonCanceledPosixSignal", + "SystemNative_InitializeConsoleBeforeRead", + "SystemNative_InitializeTerminalAndSignalHandling", + "SystemNative_INotifyAddWatch", + "SystemNative_INotifyInit", + "SystemNative_INotifyRemoveWatch", + "SystemNative_InterfaceNameToIndex", + "SystemNative_iOSSupportVersion", + "SystemNative_IsATty", + "SystemNative_Kill", + "SystemNative_LChflags", + "SystemNative_LChflagsCanSetHiddenFlag", + "SystemNative_Link", + "SystemNative_Listen", + "SystemNative_LoadLibrary", + "SystemNative_LockFileRegion", + "SystemNative_Log", + "SystemNative_LogError", + "SystemNative_LowLevelMonitor_Acquire", + "SystemNative_LowLevelMonitor_Create", + "SystemNative_LowLevelMonitor_Destroy", + "SystemNative_LowLevelMonitor_Release", + "SystemNative_LowLevelMonitor_Signal_Release", + "SystemNative_LowLevelMonitor_TimedWait", + "SystemNative_LowLevelMonitor_Wait", + "SystemNative_LSeek", + "SystemNative_LStat", + "SystemNative_MAdvise", + "SystemNative_Malloc", + "SystemNative_MapTcpState", + "SystemNative_MkDir", + "SystemNative_MkdTemp", + "SystemNative_MkFifo", + "SystemNative_MkNod", + "SystemNative_MksTemps", + "SystemNative_MMap", + "SystemNative_MProtect", + "SystemNative_MSync", + "SystemNative_MUnmap", + "SystemNative_Open", + "SystemNative_OpenDir", + "SystemNative_PathConf", + "SystemNative_Pipe", + "SystemNative_PlatformSupportsDualModeIPv4PacketInfo", + "SystemNative_Poll", + "SystemNative_PosixFAdvise", + "SystemNative_PRead", + "SystemNative_PReadV", + "SystemNative_PWrite", + "SystemNative_PWriteV", + "SystemNative_Read", + "SystemNative_ReadDirR", + "SystemNative_ReadEvents", + "SystemNative_ReadLink", + "SystemNative_ReadProcessStatusInfo", + "SystemNative_ReadStdin", + "SystemNative_Realloc", + "SystemNative_RealPath", + "SystemNative_Receive", + "SystemNative_ReceiveMessage", + "SystemNative_ReceiveSocketError", + "SystemNative_RegisterForSigChld", + "SystemNative_Rename", + "SystemNative_RmDir", + "SystemNative_SchedGetAffinity", + "SystemNative_SchedGetCpu", + "SystemNative_SchedSetAffinity", + "SystemNative_SearchPath", + "SystemNative_SearchPath_TempDirectory", + "SystemNative_Send", + "SystemNative_SendFile", + "SystemNative_SendMessage", + "SystemNative_SetAddressFamily", + "SystemNative_SetDelayedSigChildConsoleConfigurationHandler", + "SystemNative_SetErrNo", + "SystemNative_SetEUid", + "SystemNative_SetIPv4Address", + "SystemNative_SetIPv4MulticastOption", + "SystemNative_SetIPv6Address", + "SystemNative_SetIPv6MulticastOption", + "SystemNative_SetKeypadXmit", + "SystemNative_SetLingerOption", + "SystemNative_SetPort", + "SystemNative_SetPosixSignalHandler", + "SystemNative_SetPriority", + "SystemNative_SetRawSockOpt", + "SystemNative_SetReceiveTimeout", + "SystemNative_SetRLimit", + "SystemNative_SetSendTimeout", + "SystemNative_SetSignalForBreak", + "SystemNative_SetSockOpt", + "SystemNative_SetTerminalInvalidationHandler", + "SystemNative_SetWindowSize", + "SystemNative_ShmOpen", + "SystemNative_ShmUnlink", + "SystemNative_Shutdown", + "SystemNative_SNPrintF", + "SystemNative_SNPrintF_1I", + "SystemNative_SNPrintF_1S", + "SystemNative_Socket", + "SystemNative_Stat", + "SystemNative_StdinReady", + "SystemNative_StrErrorR", + "SystemNative_SymLink", + "SystemNative_Sync", + "SystemNative_SysConf", + "SystemNative_Sysctl", + "SystemNative_SysLog", + "SystemNative_TryChangeSocketEventRegistration", + "SystemNative_TryGetIPPacketInformation", + "SystemNative_TryGetUInt32OSThreadId", + "SystemNative_UninitializeConsoleAfterRead", + "SystemNative_Unlink", + "SystemNative_UTimensat", + "SystemNative_WaitForSocketEvents", + "SystemNative_WaitIdAnyExitedNoHangNoWait", + "SystemNative_WaitPidExitedNoHang", + "SystemNative_Write", + + // libSystem.Security.Cryptography.Native.Android.so + "AndroidCryptoNative_AeadCipherFinalEx", + "AndroidCryptoNative_Aes128Cbc", + "AndroidCryptoNative_Aes128Ccm", + "AndroidCryptoNative_Aes128Cfb128", + "AndroidCryptoNative_Aes128Cfb8", + "AndroidCryptoNative_Aes128Ecb", + "AndroidCryptoNative_Aes128Gcm", + "AndroidCryptoNative_Aes192Cbc", + "AndroidCryptoNative_Aes192Ccm", + "AndroidCryptoNative_Aes192Cfb128", + "AndroidCryptoNative_Aes192Cfb8", + "AndroidCryptoNative_Aes192Ecb", + "AndroidCryptoNative_Aes192Gcm", + "AndroidCryptoNative_Aes256Cbc", + "AndroidCryptoNative_Aes256Ccm", + "AndroidCryptoNative_Aes256Cfb128", + "AndroidCryptoNative_Aes256Cfb8", + "AndroidCryptoNative_Aes256Ecb", + "AndroidCryptoNative_Aes256Gcm", + "AndroidCryptoNative_BigNumToBinary", + "AndroidCryptoNative_ChaCha20Poly1305", + "AndroidCryptoNative_CipherCreate", + "AndroidCryptoNative_CipherCreatePartial", + "AndroidCryptoNative_CipherCtxSetPadding", + "AndroidCryptoNative_CipherDestroy", + "AndroidCryptoNative_CipherFinalEx", + "AndroidCryptoNative_CipherIsSupported", + "AndroidCryptoNative_CipherReset", + "AndroidCryptoNative_CipherSetKeyAndIV", + "AndroidCryptoNative_CipherSetNonceLength", + "AndroidCryptoNative_CipherSetTagLength", + "AndroidCryptoNative_CipherUpdate", + "AndroidCryptoNative_CipherUpdateAAD", + "AndroidCryptoNative_DecodeRsaSubjectPublicKeyInfo", + "AndroidCryptoNative_DeleteGlobalReference", + "AndroidCryptoNative_Des3Cbc", + "AndroidCryptoNative_Des3Cfb64", + "AndroidCryptoNative_Des3Cfb8", + "AndroidCryptoNative_Des3Ecb", + "AndroidCryptoNative_DesCbc", + "AndroidCryptoNative_DesCfb8", + "AndroidCryptoNative_DesEcb", + "AndroidCryptoNative_DsaGenerateKey", + "AndroidCryptoNative_DsaKeyCreateByExplicitParameters", + "AndroidCryptoNative_DsaSign", + "AndroidCryptoNative_DsaSignatureFieldSize", + "AndroidCryptoNative_DsaSizeP", + "AndroidCryptoNative_DsaSizeSignature", + "AndroidCryptoNative_DsaVerify", + "AndroidCryptoNative_EcdhDeriveKey", + "AndroidCryptoNative_EcDsaSign", + "AndroidCryptoNative_EcDsaSize", + "AndroidCryptoNative_EcDsaVerify", + "AndroidCryptoNative_EcKeyCreateByExplicitParameters", + "AndroidCryptoNative_EcKeyCreateByKeyParameters", + "AndroidCryptoNative_EcKeyCreateByOid", + "AndroidCryptoNative_EcKeyDestroy", + "AndroidCryptoNative_EcKeyGetCurveName", + "AndroidCryptoNative_EcKeyGetSize", + "AndroidCryptoNative_EcKeyUpRef", + "AndroidCryptoNative_GetBigNumBytes", + "AndroidCryptoNative_GetDsaParameters", + "AndroidCryptoNative_GetECCurveParameters", + "AndroidCryptoNative_GetECKeyParameters", + "AndroidCryptoNative_GetRsaParameters", + "AndroidCryptoNative_NewGlobalReference", + "AndroidCryptoNative_Pbkdf2", + "AndroidCryptoNative_RegisterRemoteCertificateValidationCallback", + "AndroidCryptoNative_RsaCreate", + "AndroidCryptoNative_RsaDestroy", + "AndroidCryptoNative_RsaGenerateKeyEx", + "AndroidCryptoNative_RsaPrivateDecrypt", + "AndroidCryptoNative_RsaPublicEncrypt", + "AndroidCryptoNative_RsaSignPrimitive", + "AndroidCryptoNative_RsaSize", + "AndroidCryptoNative_RsaUpRef", + "AndroidCryptoNative_RsaVerificationPrimitive", + "AndroidCryptoNative_SetRsaParameters", + "AndroidCryptoNative_SSLGetSupportedProtocols", + "AndroidCryptoNative_SSLStreamCreate", + "AndroidCryptoNative_SSLStreamCreateWithCertificates", + "AndroidCryptoNative_SSLStreamCreateWithKeyStorePrivateKeyEntry", + "AndroidCryptoNative_SSLStreamGetApplicationProtocol", + "AndroidCryptoNative_SSLStreamGetCipherSuite", + "AndroidCryptoNative_SSLStreamGetPeerCertificate", + "AndroidCryptoNative_SSLStreamGetPeerCertificates", + "AndroidCryptoNative_SSLStreamGetProtocol", + "AndroidCryptoNative_SSLStreamHandshake", + "AndroidCryptoNative_SSLStreamInitialize", + "AndroidCryptoNative_SSLStreamIsLocalCertificateUsed", + "AndroidCryptoNative_SSLStreamRead", + "AndroidCryptoNative_SSLStreamRelease", + "AndroidCryptoNative_SSLStreamRequestClientAuthentication", + "AndroidCryptoNative_SSLStreamSetApplicationProtocols", + "AndroidCryptoNative_SSLStreamSetEnabledProtocols", + "AndroidCryptoNative_SSLStreamSetTargetHost", + "AndroidCryptoNative_SSLStreamShutdown", + "AndroidCryptoNative_SSLStreamVerifyHostname", + "AndroidCryptoNative_SSLStreamWrite", + "AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration", + "AndroidCryptoNative_X509ChainBuild", + "AndroidCryptoNative_X509ChainCreateContext", + "AndroidCryptoNative_X509ChainDestroyContext", + "AndroidCryptoNative_X509ChainGetCertificateCount", + "AndroidCryptoNative_X509ChainGetCertificates", + "AndroidCryptoNative_X509ChainGetErrorCount", + "AndroidCryptoNative_X509ChainGetErrors", + "AndroidCryptoNative_X509ChainSetCustomTrustStore", + "AndroidCryptoNative_X509ChainValidate", + "AndroidCryptoNative_X509Decode", + "AndroidCryptoNative_X509DecodeCollection", + "AndroidCryptoNative_X509Encode", + "AndroidCryptoNative_X509ExportPkcs7", + "AndroidCryptoNative_X509GetCertificateForPrivateKeyEntry", + "AndroidCryptoNative_X509GetContentType", + "AndroidCryptoNative_X509IsKeyStorePrivateKeyEntry", + "AndroidCryptoNative_X509PublicKey", + "AndroidCryptoNative_X509StoreAddCertificate", + "AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey", + "AndroidCryptoNative_X509StoreContainsCertificate", + "AndroidCryptoNative_X509StoreDeleteEntry", + "AndroidCryptoNative_X509StoreEnumerateCertificates", + "AndroidCryptoNative_X509StoreEnumerateTrustedCertificates", + "AndroidCryptoNative_X509StoreGetPrivateKeyEntry", + "AndroidCryptoNative_X509StoreOpenDefault", + "AndroidCryptoNative_X509StoreRemoveCertificate", + "CryptoNative_EnsureOpenSslInitialized", + "CryptoNative_ErrClearError", + "CryptoNative_ErrErrorStringN", + "CryptoNative_ErrGetErrorAlloc", + "CryptoNative_ErrPeekError", + "CryptoNative_ErrPeekLastError", + "CryptoNative_ErrReasonErrorString", + "CryptoNative_EvpDigestCurrent", + "CryptoNative_EvpDigestFinalEx", + "CryptoNative_EvpDigestOneShot", + "CryptoNative_EvpDigestReset", + "CryptoNative_EvpDigestUpdate", + "CryptoNative_EvpMd5", + "CryptoNative_EvpMdCtxCopyEx", + "CryptoNative_EvpMdCtxCreate", + "CryptoNative_EvpMdCtxDestroy", + "CryptoNative_EvpMdSize", + "CryptoNative_EvpSha1", + "CryptoNative_EvpSha256", + "CryptoNative_EvpSha384", + "CryptoNative_EvpSha512", + "CryptoNative_GetMaxMdSize", + "CryptoNative_GetRandomBytes", + "CryptoNative_HmacCreate", + "CryptoNative_HmacCurrent", + "CryptoNative_HmacDestroy", + "CryptoNative_HmacFinal", + "CryptoNative_HmacOneShot", + "CryptoNative_HmacReset", + "CryptoNative_HmacUpdate", + "Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate", +}; + +template +struct PinvokeEntry +{ + std::string name; + Hash hash; + bool write_func_pointer; + + template friend + Os& operator<< (Os& os, PinvokeEntry const& p) + { + os << std::showbase << std::hex << p.hash << ", \"" << p.name << "\", "; + + if (p.write_func_pointer) { + return os << "reinterpret_cast(&" << p.name << ")"; + } + + return os << "nullptr"; + } +}; + +void print (std::ostream& os, std::string comment, std::string variable_name, auto const& seq) +{ + os << "\t//" << comment << '\n'; + os << "\tstd::array " << variable_name << " {{" << std::endl; + + for (auto const& elem : seq) { + os << "\t\t{" << elem << "}," << std::endl; + } + + os << "\t}};" << std::endl << std::endl; +} + +template +bool add_hash (std::string const& pinvoke, Hash hash, std::vector>& vec, std::unordered_set& used_cache, bool write_func_pointer) +{ + vec.emplace_back (pinvoke, hash, write_func_pointer); + if (used_cache.contains (hash)) { + std::cerr << (sizeof(Hash) == 4 ? "32" : "64") << "-bit hash collision for key '" << pinvoke << "': " << std::hex << std::showbase << hash << std::endl; + return true; + } + + used_cache.insert (hash); + return false; +} + +bool generate_hashes (std::string table_name, std::vector const& names, std::vector>& pinvokes32, std::vector>& pinvokes64, bool write_func_pointer) +{ + std::unordered_set used_pinvokes32{}; + std::unordered_set used_pinvokes64{}; + uint32_t hash32; + uint64_t hash64; + bool have_collisions = false; + + std::cout << "There are " << names.size () << " " << table_name << " p/invoke functions" << std::endl; + for (std::string const& pinvoke : names) { + have_collisions |= add_hash (pinvoke, xxhash32::hash (pinvoke.c_str (), pinvoke.length ()), pinvokes32, used_pinvokes32, write_func_pointer); + have_collisions |= add_hash (pinvoke, xxhash64::hash (pinvoke.c_str (), pinvoke.length ()), pinvokes64, used_pinvokes64, write_func_pointer); + } + + std::cout << "p/invoke hash collisions for '" << table_name << "' were " << (have_collisions ? "" : "not ") << "found" << std::endl; + + std::ranges::sort (pinvokes32, {}, &PinvokeEntry::hash); + std::ranges::sort (pinvokes64, {}, &PinvokeEntry::hash); + + return have_collisions; +} + +template +void write_library_name_hash (Hash (*hasher)(const char*, size_t), std::ostream& os, std::string library_name, std::string variable_prefix) +{ + Hash hash = hasher (library_name.c_str (), library_name.length ()); + os << "constexpr hash_t " << variable_prefix << "_library_hash = " << std::hex << hash << ";" << std::endl; +} + +template +void write_library_name_hashes (Hash (*hasher)(const char*, size_t), std::ostream& output) +{ + write_library_name_hash (hasher, output, "java-interop", "java_interop"); + write_library_name_hash (hasher, output, "xa-internal-api", "xa_internal_api"); + write_library_name_hash (hasher, output, "libSystem.Native", "system_native"); + write_library_name_hash (hasher, output, "libSystem.IO.Compression.Native", "system_io_compression_native"); + write_library_name_hash (hasher, output, "libSystem.Security.Cryptography.Native.Android", "system_security_cryptography_native_android"); + write_library_name_hash (hasher, output, "libSystem.Globalization.Native", "system_globalization_native"); +} + +int main (int argc, char **argv) +{ + if (argc < 2) { + std::cerr << "Usage: generate-pinvoke-tables OUTPUT_FILE_PATH" << std::endl << std::endl; + return 1; + } + + fs::path output_file_path {argv[1]}; + + if (fs::exists (output_file_path)) { + if (fs::is_directory (output_file_path)) { + std::cerr << "Output destination '" << output_file_path << "' is a directory" << std::endl; + return 1; + } + + fs::remove (output_file_path); + } else { + fs::path file_dir = output_file_path.parent_path (); + if (fs::exists (file_dir)) { + if (!fs::is_directory (file_dir)) { + std::cerr << "Output destination parent path points to a file ('" << file_dir << "'" << std::endl; + return 1; + } + } else if (!file_dir.empty ()) { + if (!fs::create_directories (file_dir)) { + std::cerr << "Failed to create output directory '" << file_dir << "'" << std::endl; + std::cerr << strerror (errno) << std::endl; + return 1; + } + } + } + + bool have_collisions = false; + std::vector> internal_pinvokes32{}; + std::vector> internal_pinvokes64{}; + have_collisions |= generate_hashes ("internal", internal_pinvoke_names, internal_pinvokes32, internal_pinvokes64, true); + + std::vector> dotnet_pinvokes32{}; + std::vector> dotnet_pinvokes64{}; + have_collisions |= generate_hashes ("dotnet", dotnet_pinvoke_names, dotnet_pinvokes32, dotnet_pinvokes64, false); + + std::cout << "Generating tables in file: " << output_file_path << std::endl; + + std::ofstream output {output_file_path, std::ios::binary}; + + output << "//" << std::endl; + output << "// Autogenarated file. DO NOT EDIT." << std::endl; + output << "//" << std::endl; + output << "// To regenerate run ../../../../build-tools/scripts/generate-pinvoke-tables.sh on Linux or macOS" << std::endl; + output << "// A compiler with support for C++20 ranges is required" << std::endl; + output << "//" << std::endl << std::endl; + + output << "#include " << std::endl; + output << "#include " << std::endl << std::endl; + + output << "namespace {" << std::endl; + output << "#if INTPTR_MAX == INT64_MAX" << std::endl; + print (output, "64-bit internal p/invoke table", "internal_pinvokes", internal_pinvokes64); + print (output, "64-bit DotNet p/invoke table", "dotnet_pinvokes", dotnet_pinvokes64); + output << std::endl; + write_library_name_hashes (xxhash64::hash, output); + + output << "#else" << std::endl; + + print (output, "32-bit internal p/invoke table", "internal_pinvokes", internal_pinvokes32); + print (output, "32-bit DotNet p/invoke table", "dotnet_pinvokes", dotnet_pinvokes32); + output << std::endl; + write_library_name_hashes (xxhash32::hash, output); + + output << "#endif" << std::endl << std::endl; + + output << "constexpr size_t internal_pinvokes_count = " << std::dec << std::noshowbase << internal_pinvoke_names.size () << ";" << std::endl; + output << "constexpr size_t dotnet_pinvokes_count = " << std::dec << std::noshowbase << dotnet_pinvoke_names.size () << ";" << std::endl; + output << "} // end of anonymous namespace" << std::endl; + + return have_collisions ? 1 : 0; +} + +// This serves as a quick compile-time test of the algorithm's correctness. +// The tests are copied from https://github.com/ekpyron/xxhashct/test.cpp + +template +struct constexpr_test { + static_assert (value == expected, "Compile-time hash mismatch."); +}; + +constexpr_test ("", 0), 0x2CC5D05U> constexprTest_1; +constexpr_test ("", 0), 0x36B78AE7U> constexprTest_2; +//constexpr_test ("", 0), 0xEF46DB3751D8E999ULL> constexprTest_3; +//constexpr_test ("", 0), 0xAC75FDA2929B17EFULL> constexprTest_4; +constexpr_test ("test", 4), 0x3E2023CFU> constexprTest32_5; +constexpr_test ("test", 4), 0xA9C14438U> constexprTest32_6; +//constexpr_test ("test", 4), 0x4fdcca5ddb678139ULL> constexprTest64_7; +//constexpr_test ("test", 4), 0x5A183B8150E2F651ULL> constexprTest64_8; diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 554cbd12055..2fab41760b6 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -45,12 +45,6 @@ bool Host::clr_bundle_probe (const char *path, void **data_start, int64_t *size) return *data_start != nullptr && *size > 0; } -const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept -{ - log_info (LOG_DEFAULT, "clr_pinvoke_override (\"{}\", \"{}\")", library_name, entry_point_name); - return nullptr; -} - auto Host::zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size) -> bool { log_debug (LOG_ASSEMBLY, "zip entry: {}", entry_name.get ()); diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc new file mode 100644 index 00000000000..8193e911599 --- /dev/null +++ b/src/native/clr/host/internal-pinvokes.cc @@ -0,0 +1,16 @@ +#include +#include + +using namespace xamarin::android; + +int +_monodroid_gref_get () +{ + return OSBridge::get_gc_gref_count (); +} + +int +_monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) +{ + return OSBridge::_monodroid_gref_log_new (curHandle, curType, newHandle, newType, threadName, threadId, from, from_writable); +} diff --git a/src/native/clr/host/os-bridge.cc b/src/native/clr/host/os-bridge.cc index 28b64be5744..5296893e8f7 100644 --- a/src/native/clr/host/os-bridge.cc +++ b/src/native/clr/host/os-bridge.cc @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -23,3 +24,103 @@ auto OSBridge::lref_to_gref (JNIEnv *env, jobject lref) noexcept -> jobject env->DeleteLocalRef (lref); return g; } + +auto OSBridge::_monodroid_gref_inc () noexcept -> int +{ + return __sync_add_and_fetch (&gc_gref_count, 1); +} + +auto OSBridge::_monodroid_gref_dec () noexcept -> int +{ + return __sync_sub_and_fetch (&gc_gref_count, 1); +} + +[[gnu::always_inline]] +auto OSBridge::_get_stack_trace_line_end (char *m) noexcept -> char* +{ + while (*m && *m != '\n') { + m++; + } + + return m; +} + +[[gnu::always_inline]] +void OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) noexcept +{ + char *n = const_cast (from); + + char c; + do { + char *m = n; + char *end = _get_stack_trace_line_end (m); + + n = end + 1; + c = *end; + *end = '\0'; + if ((category == LOG_GREF && Logger::gref_to_logcat ()) || + (category == LOG_LREF && Logger::lref_to_logcat ())) { + log_debug (category, "{}", optional_string (m)); + } + + if (to != nullptr) { + fprintf (to, "%s\n", optional_string (m)); + fflush (to); + } + *end = c; + } while (c); +} + +auto OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept -> int +{ + int c = _monodroid_gref_inc (); + if ((log_categories & LOG_GREF) == 0) { + return c; + } + + log_info (LOG_GREF, + "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(curHandle), + curType, + reinterpret_cast(newHandle), + newType, + optional_string (threadName), + threadId + ); + + if (Logger::gref_to_logcat ()) { + if (from_writable) { + _write_stack_trace (nullptr, const_cast(from), LOG_GREF); + } else { + log_info (LOG_GREF, "{}", optional_string (from)); + } + } + + if (Logger::gref_log () == nullptr) { + return c; + } + + fprintf ( + Logger::gref_log (), + "+g+ grefc %i gwrefc %i obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%i)\n", + c, + gc_weak_gref_count, + curHandle, + curType, + newHandle, + newType, + optional_string (threadName), + threadId + ); + + if (from_writable) { + _write_stack_trace (Logger::gref_log (), const_cast(from)); + } else { + fprintf (Logger::gref_log (), "%s\n", from); + } + + fflush (Logger::gref_log ()); + return c; +} diff --git a/src/native/clr/host/pinvoke-override.cc b/src/native/clr/host/pinvoke-override.cc new file mode 100644 index 00000000000..11fd5708a20 --- /dev/null +++ b/src/native/clr/host/pinvoke-override.cc @@ -0,0 +1,92 @@ +#include +#include +#include + +using namespace xamarin::android; + +#include "pinvoke-tables.include" + +[[gnu::flatten]] +auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const char *entrypoint_name) noexcept -> void* +{ + if (library_name == nullptr || entrypoint_name == nullptr) { + return nullptr; + } + + hash_t library_name_hash = xxhash::hash (library_name, strlen (library_name)); + hash_t entrypoint_hash = xxhash::hash (entrypoint_name, strlen (entrypoint_name)); + + if (library_name_hash == java_interop_library_hash || library_name_hash == xa_internal_api_library_hash) { + PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); + + if (entry == nullptr) [[unlikely]] { + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", + optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); + log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); + for (size_t i = 0uz; i < internal_pinvokes_count; i++) { + PinvokeEntry const& e = internal_pinvokes[i]; + log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", optional_string (e.name), e.func, e.hash); + } + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Failure handling a p/invoke request for '{}'@'{}'", + optional_string (entrypoint_name), + optional_string (library_name) + ) + ); + } + + return entry->func; + } + + // The order of statements below should be kept in the descending probability of occurrence order (as much as + // possible, of course). `libSystem.Native` is requested during early startup for each MAUI app, so its + // probability is higher, just as it's more likely that `libSystem.Security.Cryptography.Android` will be used + // in an app rather than `libSystem.IO.Compression.Native` + void **dotnet_dso_handle; // Set to a non-null value only for dotnet shared libraries + if (library_name_hash == system_native_library_hash) { + dotnet_dso_handle = &system_native_library_handle; + } else if (library_name_hash == system_security_cryptography_native_android_library_hash) { + dotnet_dso_handle = &system_security_cryptography_native_android_library_handle; + } else if (library_name_hash == system_io_compression_native_library_hash) { + dotnet_dso_handle = &system_io_compression_native_library_handle; + } else if (library_name_hash == system_globalization_native_library_hash) { + dotnet_dso_handle = &system_globalization_native_library_handle; + } else { + dotnet_dso_handle = nullptr; + } + + if (dotnet_dso_handle != nullptr) { + PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, dotnet_pinvokes.data (), dotnet_pinvokes_count); + if (entry != nullptr) { + if (entry->func != nullptr) { + return entry->func; + } + + load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); + if (entry->func == nullptr) { + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", + optional_string (entrypoint_name), optional_string (library_name)); + return nullptr; // let Mono deal with the fallout + } + + return entry->func; + } + + // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below + log_debug ( + LOG_ASSEMBLY, + "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", + optional_string (entrypoint_name), + optional_string (library_name) + ); + } + + return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); +} + +const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept +{ + return PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); +} diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include new file mode 100644 index 00000000000..49e1dc4059f --- /dev/null +++ b/src/native/clr/host/pinvoke-tables.include @@ -0,0 +1,1006 @@ +// +// Autogenarated file. DO NOT EDIT. +// +// To regenerate run ../../../../build-tools/scripts/generate-pinvoke-tables.sh on Linux or macOS +// A compiler with support for C++20 ranges is required +// + +#include +#include + +namespace { +#if INTPTR_MAX == INT64_MAX + //64-bit internal p/invoke table + std::array internal_pinvokes {{ + {0x4b1956138764939a, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, + {0xd1e121b94ea63f2e, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, + }}; + + //64-bit DotNet p/invoke table + std::array dotnet_pinvokes {{ + {0x99f2ee02463000, "CompressionNative_Crc32", nullptr}, + {0xb38afc8bfe830b, "SystemNative_Bind", nullptr}, + {0x190fe65d8736dcb, "SystemNative_TryGetIPPacketInformation", nullptr}, + {0x1c8b86562ad5772, "SystemNative_Receive", nullptr}, + {0x202543f28ecaf06, "SystemNative_Abort", nullptr}, + {0x25abeafa88904a2, "SystemNative_SetPosixSignalHandler", nullptr}, + {0x33158212a812caf, "SystemNative_GetEstimatedTcpConnectionCount", nullptr}, + {0x3511e36d0a6c1b5, "SystemNative_LockFileRegion", nullptr}, + {0x375a0e90c77ca35, "AndroidCryptoNative_EcKeyCreateByExplicitParameters", nullptr}, + {0x37b9dd562235e42, "SystemNative_MSync", nullptr}, + {0x3a5df4793dd3230, "SystemNative_INotifyInit", nullptr}, + {0x3d24547fa4fc31b, "SystemNative_GetUInt64OSThreadId", nullptr}, + {0x410f8526b1edfc3, "GlobalizationNative_GetLocaleInfoInt", nullptr}, + {0x47302bd7e277183, "AndroidCryptoNative_X509GetCertificateForPrivateKeyEntry", nullptr}, + {0x581df5b0a00c422, "SystemNative_SetRLimit", nullptr}, + {0x598db66ca39c41f, "AndroidCryptoNative_EcKeyUpRef", nullptr}, + {0x5b5ab451ff38f8e, "SystemNative_GetMaximumAddressSize", nullptr}, + {0x656cac62ccc9e3c, "AndroidCryptoNative_X509GetContentType", nullptr}, + {0x6861b5336291d12, "SystemNative_PathConf", nullptr}, + {0x690c4347972024f, "AndroidCryptoNative_Aes256Gcm", nullptr}, + {0x6a1f4deffa02c30, "SystemNative_LowLevelMonitor_Acquire", nullptr}, + {0x7b5579ab0499b1f, "AndroidCryptoNative_RsaSize", nullptr}, + {0x7ce8a9b967dd269, "SystemNative_Read", nullptr}, + {0x7f0e1227c9c0225, "CryptoNative_EvpMdCtxDestroy", nullptr}, + {0x8352ae4bba2b83b, "SystemNative_SetSendTimeout", nullptr}, + {0x98bd27a7461321d, "SystemNative_Dup", nullptr}, + {0x9a39fbf59eed9f9, "CryptoNative_EvpSha1", nullptr}, + {0xa4aeeaff9ca2d10, "BrotliDecoderDecompressStream", nullptr}, + {0xa906c14ca5834bc, "SystemNative_GetEUid", nullptr}, + {0xac9f9c1abb62a92, "SystemNative_Log", nullptr}, + {0xadb2441bcfcdfe9, "SystemNative_CreateThread", nullptr}, + {0xafbf5c69d1badc0, "SystemNative_SetTerminalInvalidationHandler", nullptr}, + {0xba897b7abe67b16, "SystemNative_FcntlSetPipeSz", nullptr}, + {0xc305c22ce7ab8a0, "SystemNative_SetSockOpt", nullptr}, + {0xc79e924361c15ca, "SystemNative_RealPath", nullptr}, + {0xcaba893801c6a6f, "AndroidCryptoNative_Aes256Ecb", nullptr}, + {0xcbe6d3d22131194, "AndroidCryptoNative_SetRsaParameters", nullptr}, + {0xe7e93cf9237e1f2, "GlobalizationNative_ToAscii", nullptr}, + {0xef8dd67e25bac53, "SystemNative_GetWindowSize", nullptr}, + {0xfa0899cf8d00a87, "SystemNative_MkDir", nullptr}, + {0xfe7079441ac127e, "SystemNative_CreateSocketEventPort", nullptr}, + {0x1027786cdd9a3e9c, "AndroidCryptoNative_Aes192Cbc", nullptr}, + {0x10d733abd1fd94bb, "SystemNative_TryChangeSocketEventRegistration", nullptr}, + {0x114b8384553f5418, "SystemNative_GetSystemTimeAsTicks", nullptr}, + {0x119a38c3e288a233, "SystemNative_SNPrintF_1S", nullptr}, + {0x11b6f4f0aafeda95, "SystemNative_LowLevelMonitor_TimedWait", nullptr}, + {0x11cc73f2926d4064, "SystemNative_ConfigureTerminalForChildProcess", nullptr}, + {0x121bc483ac26f5f8, "SystemNative_GetGroupName", nullptr}, + {0x12d65f9f65b01497, "SystemNative_GetRawSockOpt", nullptr}, + {0x12eaf09505dc19fd, "SystemNative_FStat", nullptr}, + {0x13577369f5ec4b0a, "SystemNative_GetActiveTcpConnectionInfos", nullptr}, + {0x1399413d8a7d9dd8, "SystemNative_GetAddressFamily", nullptr}, + {0x13a1c2de7fb2519f, "SystemNative_CloseSocketEventPort", nullptr}, + {0x146cd1dc4fb2ba58, "SystemNative_LChflagsCanSetHiddenFlag", nullptr}, + {0x14b7e3527b60e83f, "CryptoNative_ErrErrorStringN", nullptr}, + {0x15bd710d3a9b3b0c, "CryptoNative_EvpDigestFinalEx", nullptr}, + {0x176e22ea7c580dae, "SystemNative_ReadDirR", nullptr}, + {0x18580a4592ed1ea6, "GlobalizationNative_GetSortKey", nullptr}, + {0x185f5d25252c3c72, "SystemNative_FAllocate", nullptr}, + {0x18d6b5e9fec9b0dc, "SystemNative_Connectx", nullptr}, + {0x18f7da5f584b5b59, "SystemNative_PReadV", nullptr}, + {0x1948a0cf88329c2f, "SystemNative_HandleNonCanceledPosixSignal", nullptr}, + {0x1ac95b02f23933cc, "SystemNative_CanGetHiddenFlag", nullptr}, + {0x1d1bb0528d517729, "AndroidCryptoNative_SSLGetSupportedProtocols", nullptr}, + {0x1d4dcbc06728e689, "SystemNative_Close", nullptr}, + {0x1d6d4278ffbbab77, "SystemNative_Pipe", nullptr}, + {0x1d8d6a688fc5bfb3, "SystemNative_SendFile", nullptr}, + {0x1e6228e955989698, "AndroidCryptoNative_EcKeyCreateByOid", nullptr}, + {0x1e8edcc515cd23f9, "CryptoNative_EvpDigestOneShot", nullptr}, + {0x1f1c61a157636aad, "SystemNative_Stat", nullptr}, + {0x1f45ac9d3c6b1554, "AndroidCryptoNative_SSLStreamGetCipherSuite", nullptr}, + {0x1f72f52873ced9c9, "GlobalizationNative_InitOrdinalCasingPage", nullptr}, + {0x1f7d2360a1cdcbff, "AndroidCryptoNative_SSLStreamCreate", nullptr}, + {0x1f849e45a3014a9f, "SystemNative_GetIPv6Address", nullptr}, + {0x1f9361fc7b624c1b, "SystemNative_LowLevelMonitor_Wait", nullptr}, + {0x205a31e661496019, "CryptoNative_ErrGetErrorAlloc", nullptr}, + {0x20784dcc7e9cee75, "BrotliGetTransforms", nullptr}, + {0x2178ba302d0c5f1c, "GlobalizationNative_GetCalendars", nullptr}, + {0x218fce505a140c55, "AndroidCryptoNative_EcDsaVerify", nullptr}, + {0x2291e0ba4e1b55b0, "SystemNative_LStat", nullptr}, + {0x23ac2a4c4d1c744e, "AndroidCryptoNative_X509ChainGetCertificateCount", nullptr}, + {0x24f840f903a26ded, "SystemNative_ConvertErrorPalToPlatform", nullptr}, + {0x24ff74e427d0626e, "SystemNative_GetErrNo", nullptr}, + {0x254905036a0061cf, "SystemNative_CreateSocketEventBuffer", nullptr}, + {0x255c4a2e297fd9f5, "SystemNative_INotifyAddWatch", nullptr}, + {0x267c94097a3bf1f3, "AndroidCryptoNative_CipherDestroy", nullptr}, + {0x27944922cd8283ca, "CryptoNative_EvpSha384", nullptr}, + {0x2795a01c2c64aea1, "CryptoNative_HmacReset", nullptr}, + {0x27f3d9266af2b315, "SystemNative_GetIPv4Address", nullptr}, + {0x2925953889c48cab, "SystemNative_CreateNetworkChangeListenerSocket", nullptr}, + {0x2a49948ae20571cb, "SystemNative_SchedGetAffinity", nullptr}, + {0x2b45d7cdf6e8e0c7, "AndroidCryptoNative_X509StoreDeleteEntry", nullptr}, + {0x2c352dd7c367e438, "CryptoNative_EvpSha512", nullptr}, + {0x2c7e5e179cc917cb, "AndroidCryptoNative_DsaSizeSignature", nullptr}, + {0x2c8da1192c5d7d2b, "SystemNative_FLock", nullptr}, + {0x2d64b1ac218cf29e, "SystemNative_AlignedRealloc", nullptr}, + {0x2e1102c297588e10, "BrotliEncoderDestroyInstance", nullptr}, + {0x2e429d96a9fc92bd, "SystemNative_InitializeTerminalAndSignalHandling", nullptr}, + {0x2fdcf708ff792105, "AndroidCryptoNative_SSLStreamVerifyHostname", nullptr}, + {0x301c465c1ac0adf9, "SystemNative_MProtect", nullptr}, + {0x307db94ae9f929e5, "CryptoNative_GetMaxMdSize", nullptr}, + {0x31027564deeb71b0, "AndroidCryptoNative_Aes128Cbc", nullptr}, + {0x32e594690358a960, "GlobalizationNative_GetLocaleInfoString", nullptr}, + {0x3319a5483b3cc1fc, "SystemNative_GetRLimit", nullptr}, + {0x3424ffcb69ecef57, "SystemNative_Unlink", nullptr}, + {0x346a9bb11364833c, "SystemNative_DrainAutoreleasePool", nullptr}, + {0x35169e67cc0f8529, "SystemNative_GetIPv6MulticastOption", nullptr}, + {0x359205b4a10fa780, "SystemNative_LowLevelMonitor_Destroy", nullptr}, + {0x35c1fa8dffcbbd8c, "CryptoNative_EvpDigestReset", nullptr}, + {0x36128eed665b1923, "SystemNative_ShmUnlink", nullptr}, + {0x364dcf65ae63adff, "SystemNative_GetSocketErrorOption", nullptr}, + {0x3757b327944abb54, "SystemNative_EnablePosixSignalHandling", nullptr}, + {0x38b4bd21127ceffd, "SystemNative_StrErrorR", nullptr}, + {0x38c7de719e8ae69d, "SystemNative_RmDir", nullptr}, + {0x391bbbb9bbde4455, "SystemNative_SetIPv4MulticastOption", nullptr}, + {0x3a7245f3ea476bf7, "SystemNative_SNPrintF", nullptr}, + {0x3ae92e4198427b0d, "SystemNative_ReadLink", nullptr}, + {0x3e0de839e6cfa6e5, "SystemNative_Accept", nullptr}, + {0x3e7cf9a4789a31c7, "SystemNative_FChflags", nullptr}, + {0x3f19a16a3230b551, "AndroidCryptoNative_ChaCha20Poly1305", nullptr}, + {0x3f49b6278f04ae84, "SystemNative_Disconnect", nullptr}, + {0x3fba15600bf0f229, "SystemNative_SetEUid", nullptr}, + {0x401935ffc3454bb1, "AndroidCryptoNative_X509PublicKey", nullptr}, + {0x403e1bc0b3baba84, "CompressionNative_Inflate", nullptr}, + {0x40bfa1211f5f6f9c, "AndroidCryptoNative_EcKeyGetCurveName", nullptr}, + {0x40d61d78487edb08, "GlobalizationNative_GetICUVersion", nullptr}, + {0x41b6e7f32da99fa9, "AndroidCryptoNative_X509ChainDestroyContext", nullptr}, + {0x41c169fb0e30a390, "AndroidCryptoNative_X509ChainGetErrorCount", nullptr}, + {0x41c1f2c9153639af, "SystemNative_FUTimens", nullptr}, + {0x420718c398131a55, "AndroidCryptoNative_SSLStreamGetProtocol", nullptr}, + {0x42339dd2717504d9, "SystemNative_GetLingerOption", nullptr}, + {0x42783107bf2935ec, "SystemNative_FreeHostEntry", nullptr}, + {0x42eb0578a9d62b78, "SystemNative_GetFormatInfoForMountPoint", nullptr}, + {0x4360eb8a25122eee, "GlobalizationNative_StartsWith", nullptr}, + {0x43741165a5ba60d5, "AndroidCryptoNative_CipherUpdateAAD", nullptr}, + {0x44ccb27979f980ce, "SystemNative_AlignedAlloc", nullptr}, + {0x44f1a5c46033eec2, "SystemNative_SysLog", nullptr}, + {0x469898c8d892af83, "BrotliEncoderCompress", nullptr}, + {0x483b434d7b089c7e, "SystemNative_Write", nullptr}, + {0x4845e1c76265acc9, "AndroidCryptoNative_X509StoreEnumerateCertificates", nullptr}, + {0x484a3a445bdb14fc, "SystemNative_GetOSArchitecture", nullptr}, + {0x4909639a9d87bdb5, "SystemNative_AlignedFree", nullptr}, + {0x49e3ba95feb79c6c, "SystemNative_SetAddressFamily", nullptr}, + {0x4a7272ac9d117f2d, "AndroidCryptoNative_EcKeyDestroy", nullptr}, + {0x4b00795bbeea6f60, "SystemNative_SetIPv6Address", nullptr}, + {0x4bd4b1c0803c8c55, "GlobalizationNative_GetLocaleName", nullptr}, + {0x4be7ceca50f3298c, "SystemNative_LowLevelMonitor_Create", nullptr}, + {0x4bec4a1d7dfd4cf7, "SystemNative_GetUnixRelease", nullptr}, + {0x4bfff22801b209ca, "SystemNative_LChflags", nullptr}, + {0x4c22cc4f2b1dab26, "SystemNative_SetPriority", nullptr}, + {0x4c5d96426f92c29d, "CryptoNative_HmacUpdate", nullptr}, + {0x4d6361e5095cff36, "AndroidCryptoNative_DsaSign", nullptr}, + {0x4d74053b37e582fa, "AndroidCryptoNative_X509ChainCreateContext", nullptr}, + {0x4f22643b9509cc12, "GlobalizationNative_IsNormalized", nullptr}, + {0x501daf7e3a890220, "AndroidCryptoNative_X509ChainBuild", nullptr}, + {0x507983f11ffec7a8, "GlobalizationNative_GetTimeZoneDisplayName", nullptr}, + {0x509ff12da4e77259, "SystemNative_GetSocketAddressSizes", nullptr}, + {0x523240c01d14ad50, "SystemNative_GetPeerID", nullptr}, + {0x52794f1118d32f08, "SystemNative_GetUnixVersion", nullptr}, + {0x52fc107ebdb6fcc7, "AndroidCryptoNative_X509StoreRemoveCertificate", nullptr}, + {0x5381564d2c06c0a3, "SystemNative_SysConf", nullptr}, + {0x54ec3421ab70a40a, "Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate", nullptr}, + {0x556bc89d2d4dfc85, "SystemNative_GetDeviceIdentifiers", nullptr}, + {0x558250d199e906bb, "CryptoNative_ErrReasonErrorString", nullptr}, + {0x5592a052ceb4caf6, "SystemNative_GetProcessPath", nullptr}, + {0x55fe2620f63d83d8, "SystemNative_SetDelayedSigChildConsoleConfigurationHandler", nullptr}, + {0x56e982948d00f10d, "GlobalizationNative_IndexOf", nullptr}, + {0x574d77a68ec3e488, "SystemNative_GetEnv", nullptr}, + {0x5755d1cd0c158620, "BrotliDecoderSetParameter", nullptr}, + {0x580dda20ac9e83c6, "BrotliEncoderSetParameter", nullptr}, + {0x583db0344a1cd715, "SystemNative_GetActiveUdpListeners", nullptr}, + {0x5908581fe73717f0, "SystemNative_InterfaceNameToIndex", nullptr}, + {0x5916efc3e1e49137, "CryptoNative_ErrPeekError", nullptr}, + {0x5a114024ecd1162c, "CryptoNative_EvpDigestUpdate", nullptr}, + {0x5a305cf2a314d6a6, "SystemNative_FTruncate", nullptr}, + {0x5a337d9cc7d8bcfd, "CryptoNative_HmacCurrent", nullptr}, + {0x5d503db70d17dad2, "BrotliEncoderIsFinished", nullptr}, + {0x5dd1d1d024378765, "CryptoNative_EvpMdSize", nullptr}, + {0x5e53b688fede3216, "SystemNative_GetControlCharacters", nullptr}, + {0x5fa62856bdbba9c0, "SystemNative_GetPort", nullptr}, + {0x5fd29ac523ff6e3d, "AndroidCryptoNative_SSLStreamRelease", nullptr}, + {0x5ffae3c8023a80b8, "AndroidCryptoNative_SSLStreamGetPeerCertificate", nullptr}, + {0x600b4418896f7808, "SystemNative_Exit", nullptr}, + {0x6089f0c8112eb3d9, "SystemNative_InitializeConsoleBeforeRead", nullptr}, + {0x613307e537d462db, "SystemNative_GetReadDirRBufferSize", nullptr}, + {0x61bacd7170fd8c9b, "SystemNative_SchedSetAffinity", nullptr}, + {0x61f3ce1b18b20d6f, "SystemNative_GetNativeIPInterfaceStatistics", nullptr}, + {0x62351df42d842942, "SystemNative_GetSignalForBreak", nullptr}, + {0x635327a9b09a910d, "GlobalizationNative_NormalizeString", nullptr}, + {0x6393d30aceaa6df2, "SystemNative_PWriteV", nullptr}, + {0x6448f0806bd3a338, "SystemNative_FreeEnviron", nullptr}, + {0x648a9b317bc64fe0, "AndroidCryptoNative_RsaGenerateKeyEx", nullptr}, + {0x650eddee76c6b8da, "SystemNative_GetHostName", nullptr}, + {0x652badfba5d61929, "SystemNative_FcntlSetFD", nullptr}, + {0x66e049fe27bf91ea, "AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration", nullptr}, + {0x6792c0a7ea5d19c9, "BrotliEncoderTakeOutput", nullptr}, + {0x67a8868ef592a3fd, "AndroidCryptoNative_SSLStreamShutdown", nullptr}, + {0x67a9b5bbce322f8c, "AndroidCryptoNative_Des3Cbc", nullptr}, + {0x67d2cd86792b1d0c, "SystemNative_Realloc", nullptr}, + {0x67e9d60481f4be06, "SystemNative_PlatformSupportsDualModeIPv4PacketInfo", nullptr}, + {0x68df81a8fb5bf442, "SystemNative_GetSockOpt", nullptr}, + {0x68f3fe6083c0355b, "SystemNative_GetLoadLibraryError", nullptr}, + {0x69ad99fac0467f64, "SystemNative_Link", nullptr}, + {0x6a59d9242cd31785, "AndroidCryptoNative_RsaPrivateDecrypt", nullptr}, + {0x6ac3aeecfc75bfad, "GlobalizationNative_GetSortVersion", nullptr}, + {0x6b9097385aa77917, "SystemNative_FSync", nullptr}, + {0x6b9bce16ba8e845f, "SystemNative_Malloc", nullptr}, + {0x6bc18fbbbf267e2a, "SystemNative_ReceiveSocketError", nullptr}, + {0x6d566e1f6e5a2d8f, "BrotliDefaultAllocFunc", nullptr}, + {0x6dbd90e9cc86310b, "AndroidCryptoNative_CipherFinalEx", nullptr}, + {0x6dfd40c2dd0d7382, "AndroidCryptoNative_RsaUpRef", nullptr}, + {0x6e2c1caff08e6e2d, "SystemNative_ReadStdin", nullptr}, + {0x6ee05d5e8650e56c, "SystemNative_DisablePosixSignalHandling", nullptr}, + {0x6f990f1f7bc80630, "AndroidCryptoNative_RsaCreate", nullptr}, + {0x70f907b97d3fe059, "AndroidCryptoNative_Aes192Ccm", nullptr}, + {0x7150f0eb40797bb3, "AndroidCryptoNative_SSLStreamCreateWithCertificates", nullptr}, + {0x724820d307055ed1, "CryptoNative_HmacFinal", nullptr}, + {0x729afe37cdb8ae8f, "SystemNative_Connect", nullptr}, + {0x730ae9a7469a7321, "SystemNative_GetAllMountPoints", nullptr}, + {0x7356b141407d261e, "AndroidCryptoNative_EcdhDeriveKey", nullptr}, + {0x742da00b2dbf435d, "SystemNative_LoadLibrary", nullptr}, + {0x74ec4a8d869776ad, "AndroidCryptoNative_Aes128Ccm", nullptr}, + {0x7559feb379d38da5, "SystemNative_GetTimeZoneData", nullptr}, + {0x758dfbf057da0da0, "AndroidCryptoNative_DsaSignatureFieldSize", nullptr}, + {0x77ca6a148e5a51d9, "GlobalizationNative_IanaIdToWindowsId", nullptr}, + {0x7975d1d7029cf1a3, "AndroidCryptoNative_Aes128Gcm", nullptr}, + {0x79f5c24afbd04af1, "AndroidCryptoNative_Aes256Cbc", nullptr}, + {0x7a37e0d077f2dfe5, "AndroidCryptoNative_DsaGenerateKey", nullptr}, + {0x7a4d912694906c9c, "GlobalizationNative_ToUnicode", nullptr}, + {0x7af1f52a7a632e95, "BrotliDecoderTakeOutput", nullptr}, + {0x7d5273ad530e7298, "AndroidCryptoNative_X509StoreOpenDefault", nullptr}, + {0x7d7ee4bce74d4de9, "SystemNative_GetDomainSocketSizes", nullptr}, + {0x7e1766c6df3ad261, "SystemNative_MUnmap", nullptr}, + {0x7e4bdf46d4ff9f11, "SystemNative_MkNod", nullptr}, + {0x7e5fa2f70891c7fe, "GlobalizationNative_ChangeCaseTurkish", nullptr}, + {0x7ec328b6ba9eab8a, "SystemNative_WaitForSocketEvents", nullptr}, + {0x7fa96d0284954375, "AndroidCryptoNative_X509Decode", nullptr}, + {0x80ef5040fdcc248d, "BrotliEncoderMaxCompressedSize", nullptr}, + {0x813bedf08c3388d4, "AndroidCryptoNative_Aes128Cfb8", nullptr}, + {0x84c8a7489b37fea0, "SystemNative_GetPlatformSignalNumber", nullptr}, + {0x84cc0301870c37ce, "AndroidCryptoNative_SSLStreamSetTargetHost", nullptr}, + {0x8502eeba98158e79, "SystemNative_FcntlSetIsNonBlocking", nullptr}, + {0x8530d37777969db6, "SystemNative_SetKeypadXmit", nullptr}, + {0x85d0033bc38bb4bb, "SystemNative_MAdvise", nullptr}, + {0x868e09dc7dfea364, "AndroidCryptoNative_RsaSignPrimitive", nullptr}, + {0x870191ad244b8069, "AndroidCryptoNative_RegisterRemoteCertificateValidationCallback", nullptr}, + {0x87019b7831c0c34c, "AndroidCryptoNative_Aes192Gcm", nullptr}, + {0x87c447e7f873cff0, "AndroidCryptoNative_X509ChainValidate", nullptr}, + {0x889350f209555ecb, "SystemNative_MkdTemp", nullptr}, + {0x88a08b60b80c70cc, "SystemNative_FChMod", nullptr}, + {0x88cfeefc903f9d60, "CryptoNative_EvpDigestCurrent", nullptr}, + {0x8bcabce135063bed, "SystemNative_OpenDir", nullptr}, + {0x8df448aee6e8fa5e, "SystemNative_WaitPidExitedNoHang", nullptr}, + {0x8e96cb02418947cc, "SystemNative_FcntlGetPipeSz", nullptr}, + {0x8fb6ed14ee0256bc, "SystemNative_GetTimestamp", nullptr}, + {0x8ffe2d950d138c01, "SystemNative_SchedGetCpu", nullptr}, + {0x9039632237d70ae7, "AndroidCryptoNative_NewGlobalReference", nullptr}, + {0x9161ade1206fd86e, "AndroidCryptoNative_Aes256Cfb128", nullptr}, + {0x9167a072639a7c95, "AndroidCryptoNative_Aes256Ccm", nullptr}, + {0x91f065ec0d3aec55, "AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey", nullptr}, + {0x93a8bec488055608, "SystemNative_GetPwNamR", nullptr}, + {0x95a0e2fc5c0cb49e, "AndroidCryptoNative_SSLStreamSetApplicationProtocols", nullptr}, + {0x95a4cb8563cc6b14, "SystemNative_ShmOpen", nullptr}, + {0x9856fa59ed936b73, "SystemNative_GetSid", nullptr}, + {0x996ada1c038aabba, "SystemNative_MksTemps", nullptr}, + {0x9991a277809ef205, "AndroidCryptoNative_SSLStreamGetApplicationProtocol", nullptr}, + {0x99a840c495204202, "SystemNative_GetBytesAvailable", nullptr}, + {0x99e3660fc483d7be, "CryptoNative_GetRandomBytes", nullptr}, + {0x9aa9eaee3dd8b23b, "SystemNative_GetIPv4MulticastOption", nullptr}, + {0x9aaaad33b28af82f, "SystemNative_SetSignalForBreak", nullptr}, + {0x9aab07f824659d3e, "AndroidCryptoNative_DsaKeyCreateByExplicitParameters", nullptr}, + {0x9c3e8b890033819a, "SystemNative_FcntlCanGetSetPipeSz", nullptr}, + {0x9c832cd7fcbf2de0, "SystemNative_MkFifo", nullptr}, + {0x9d2cb31282abd3d9, "SystemNative_GetNetworkInterfaces", nullptr}, + {0x9e25ebf4f61cc299, "SystemNative_ChDir", nullptr}, + {0x9e79166979634030, "AndroidCryptoNative_CipherSetKeyAndIV", nullptr}, + {0x9edddf30d660eff4, "AndroidCryptoNative_Aes192Ecb", nullptr}, + {0x9fb01da1222e905a, "SystemNative_IsATty", nullptr}, + {0xa193402ff5140ac1, "GlobalizationNative_GetCalendarInfo", nullptr}, + {0xa1e881a63614507e, "SystemNative_INotifyRemoveWatch", nullptr}, + {0xa2254fea4d8b6909, "SystemNative_MMap", nullptr}, + {0xa272b5349013d9ef, "CryptoNative_EvpSha256", nullptr}, + {0xa2d7790a850024c0, "SystemNative_GetNumRoutes", nullptr}, + {0xa302613a430248b8, "SystemNative_GetGroups", nullptr}, + {0xa308025a784497df, "AndroidCryptoNative_SSLStreamSetEnabledProtocols", nullptr}, + {0xa56532a23755cd87, "SystemNative_StdinReady", nullptr}, + {0xa56954e28eb9a9c9, "AndroidCryptoNative_Des3Cfb8", nullptr}, + {0xa57e18f82abd5958, "BrotliDecoderDestroyInstance", nullptr}, + {0xa5eda72b95fe78c3, "AndroidCryptoNative_X509ChainGetErrors", nullptr}, + {0xa831a683f743e417, "GlobalizationNative_WindowsIdToIanaId", nullptr}, + {0xa89b70c38d3ba079, "CryptoNative_HmacCreate", nullptr}, + {0xa89ec9958d999483, "SystemNative_GetCwd", nullptr}, + {0xa8bdc3e7ee898dfc, "SystemNative_Shutdown", nullptr}, + {0xa93eb533acf7564d, "AndroidCryptoNative_DesEcb", nullptr}, + {0xa94b1cf083978da9, "CryptoNative_EvpMdCtxCopyEx", nullptr}, + {0xa961e8db31830e16, "AndroidCryptoNative_Aes192Cfb8", nullptr}, + {0xaa8f0f87ae474ffe, "AndroidCryptoNative_SSLStreamCreateWithKeyStorePrivateKeyEntry", nullptr}, + {0xabdcf2f74d210f35, "SystemNative_GetCryptographicallySecureRandomBytes", nullptr}, + {0xac11eab9d9c31b01, "SystemNative_UTimensat", nullptr}, + {0xac5c6a70d140a4bf, "GlobalizationNative_GetLocaleTimeFormat", nullptr}, + {0xac7725c652a5fb5b, "SystemNative_CopyFile", nullptr}, + {0xad1a2d6575cdd4e3, "AndroidCryptoNative_SSLStreamWrite", nullptr}, + {0xad228cdc4edb11d6, "SystemNative_CloseDir", nullptr}, + {0xadc6889903a2d6f4, "SystemNative_Rename", nullptr}, + {0xae320903718eb45d, "SystemNative_MapTcpState", nullptr}, + {0xae82e9ceae24192d, "AndroidCryptoNative_Pbkdf2", nullptr}, + {0xaf72b94c4acee897, "BrotliDecoderHasMoreOutput", nullptr}, + {0xaf9706efc72c3904, "SystemNative_SetIPv6MulticastOption", nullptr}, + {0xafd9f6338cdbadd4, "SystemNative_GetHostEntryForName", nullptr}, + {0xafe3d21bbaa71464, "CompressionNative_DeflateEnd", nullptr}, + {0xb0b66a7145de350d, "SystemNative_Access", nullptr}, + {0xb0df46ff09c57741, "AndroidCryptoNative_GetRsaParameters", nullptr}, + {0xb0e18377ed603e0b, "SystemNative_GetGroupList", nullptr}, + {0xb1c394b9992bd67d, "AndroidCryptoNative_EcDsaSign", nullptr}, + {0xb1ff12f3bd735982, "AndroidCryptoNative_AeadCipherFinalEx", nullptr}, + {0xb361006446f560e8, "SystemNative_LogError", nullptr}, + {0xb3e1e5e50cde576e, "BrotliEncoderVersion", nullptr}, + {0xb41fa43cc5c261cb, "BrotliDecoderGetErrorCode", nullptr}, + {0xb4996dd1aba38200, "AndroidCryptoNative_EcDsaSize", nullptr}, + {0xb516027cb59e6541, "BrotliDecoderIsFinished", nullptr}, + {0xb575ec01a7a79f8f, "AndroidCryptoNative_DesCfb8", nullptr}, + {0xb600c44028c1743d, "SystemNative_Socket", nullptr}, + {0xb632e9bc6f7be0a9, "SystemNative_GetSockName", nullptr}, + {0xb6540b73eff28747, "SystemNative_SetRawSockOpt", nullptr}, + {0xb66be1550d27bfb4, "AndroidCryptoNative_GetECCurveParameters", nullptr}, + {0xb69c3cc8b9f6a724, "BrotliDecoderIsUsed", nullptr}, + {0xb6ab9abf7887911f, "SystemNative_ReadEvents", nullptr}, + {0xb73c597de01bc0b2, "SystemNative_GetPwUidR", nullptr}, + {0xb78af5975603cd20, "SystemNative_Sync", nullptr}, + {0xb7bbbe2c16a565c6, "SystemNative_Calloc", nullptr}, + {0xb81236cd1fe85cc9, "GlobalizationNative_GetLatestJapaneseEra", nullptr}, + {0xb828d9e7df5437a5, "BrotliDecoderErrorString", nullptr}, + {0xb95350c7ec77bc72, "GlobalizationNative_ChangeCase", nullptr}, + {0xba2f6d298f3be8bc, "CryptoNative_EvpMd5", nullptr}, + {0xbb3343826d504870, "SystemNative_GetBootTimeTicks", nullptr}, + {0xbb5e970ecb6745da, "SystemNative_SymLink", nullptr}, + {0xbbd20cce92ec2c12, "SystemNative_FcntlGetFD", nullptr}, + {0xbcd9e53d2d288094, "SystemNative_GetNameInfo", nullptr}, + {0xbd5a0be2f7904089, "AndroidCryptoNative_X509StoreAddCertificate", nullptr}, + {0xbd89ef4df5486744, "SystemNative_Send", nullptr}, + {0xbdbbd2898347c0d1, "AndroidCryptoNative_SSLStreamHandshake", nullptr}, + {0xbdd3128e77381b01, "SystemNative_EnumerateInterfaceAddresses", nullptr}, + {0xbe8df478de07c6d8, "BrotliDefaultFreeFunc", nullptr}, + {0xc00ebc097b776c1f, "SystemNative_GetPriority", nullptr}, + {0xc036b23d88fad91b, "SystemNative_iOSSupportVersion", nullptr}, + {0xc0bb2dd0c5b74436, "CryptoNative_EnsureOpenSslInitialized", nullptr}, + {0xc10e411c989a9314, "CompressionNative_Deflate", nullptr}, + {0xc11cd661db8be230, "AndroidCryptoNative_Des3Cfb64", nullptr}, + {0xc183a0550feea0d6, "BrotliEncoderCompressStream", nullptr}, + {0xc19b94823ea1d39e, "CryptoNative_HmacOneShot", nullptr}, + {0xc1b8a5f1c799e4bb, "BrotliGetDictionary", nullptr}, + {0xc1c679eefc134d31, "SystemNative_LowLevelMonitor_Release", nullptr}, + {0xc287daf58054a21d, "GlobalizationNative_EndsWith", nullptr}, + {0xc2d5e1c465b2f5b6, "AndroidCryptoNative_DsaSizeP", nullptr}, + {0xc3145e336c38379b, "AndroidCryptoNative_SSLStreamGetPeerCertificates", nullptr}, + {0xc3c10021b10ba455, "SystemNative_GetEGid", nullptr}, + {0xc3fe9394fe1f3f02, "SystemNative_GetSocketType", nullptr}, + {0xc560d9947ab2a34d, "SystemNative_RegisterForSigChld", nullptr}, + {0xc5bed971846027de, "SystemNative_GetCpuUtilization", nullptr}, + {0xc69433678dd341ca, "SystemNative_ForkAndExecProcess", nullptr}, + {0xc7815e0476511544, "AndroidCryptoNative_X509Encode", nullptr}, + {0xc7ae1b8d93af5d73, "SystemNative_ChMod", nullptr}, + {0xc7d536c0e7eb3fe2, "SystemNative_FreeSocketEventBuffer", nullptr}, + {0xc7f81d5b58b65ac0, "BrotliEncoderCreateInstance", nullptr}, + {0xc87a5ee4869035c6, "SystemNative_UninitializeConsoleAfterRead", nullptr}, + {0xc8a52a8b6d96b32b, "AndroidCryptoNative_X509ExportPkcs7", nullptr}, + {0xc8b772178f955d87, "GlobalizationNative_GetSortHandle", nullptr}, + {0xc93df58ae5457bfd, "SystemNative_GetControlMessageBufferSize", nullptr}, + {0xc956e528f995739c, "SystemNative_ReceiveMessage", nullptr}, + {0xca001af79c0d7a8b, "CompressionNative_InflateEnd", nullptr}, + {0xca48c3927c202794, "AndroidCryptoNative_GetECKeyParameters", nullptr}, + {0xcaae6d345ba32c7b, "SystemNative_Kill", nullptr}, + {0xcaec08aa13779f7f, "SystemNative_GetEnviron", nullptr}, + {0xcaf599a20538b10b, "SystemNative_SetWindowSize", nullptr}, + {0xcb4bcdafdc81d116, "AndroidCryptoNative_CipherCreatePartial", nullptr}, + {0xcbbb90469d28cded, "SystemNative_SearchPath", nullptr}, + {0xcc433093c073719e, "AndroidCryptoNative_SSLStreamRead", nullptr}, + {0xcc43d880192dd6ff, "SystemNative_ConvertErrorPlatformToPal", nullptr}, + {0xcc788c0474c3e178, "SystemNative_LSeek", nullptr}, + {0xcd5d8a63493f5e38, "CompressionNative_InflateInit2_", nullptr}, + {0xcdcb014df9a6eae2, "SystemNative_SetPort", nullptr}, + {0xce36e2e1a139a020, "SystemNative_GetDefaultTimeZone", nullptr}, + {0xce6ddfe40fed99d9, "SystemNative_PRead", nullptr}, + {0xce9f8a6ac705faa5, "AndroidCryptoNative_X509DecodeCollection", nullptr}, + {0xceba527295694651, "BrotliDecoderCreateInstance", nullptr}, + {0xd0899515dfe85287, "GlobalizationNative_LoadICU", nullptr}, + {0xd185dfe303ab91dd, "GlobalizationNative_CompareString", nullptr}, + {0xd392d6ed5dcc111c, "SystemNative_GetDomainName", nullptr}, + {0xd5264d57a926edfb, "GlobalizationNative_InitICUFunctions", nullptr}, + {0xd55437b16dc84f3b, "SystemNative_GetIPv4GlobalStatistics", nullptr}, + {0xd5c063a90ae882c1, "AndroidCryptoNative_CipherIsSupported", nullptr}, + {0xd7d818c7640598dc, "AndroidCryptoNative_X509ChainGetCertificates", nullptr}, + {0xd7f1a8f616897ace, "AndroidCryptoNative_Aes256Cfb8", nullptr}, + {0xd88be8f9e9f28e90, "SystemNative_GetIcmpv4GlobalStatistics", nullptr}, + {0xd8976692c4c68818, "SystemNative_GetEstimatedUdpListenerCount", nullptr}, + {0xd8a9e47b6ca78448, "CryptoNative_ErrPeekLastError", nullptr}, + {0xd995e71361e6ed2e, "GlobalizationNative_IsPredefinedLocale", nullptr}, + {0xd9bd0b370726ce34, "AndroidCryptoNative_CipherReset", nullptr}, + {0xda05c57c78aa6706, "SystemNative_LowLevelMonitor_Signal_Release", nullptr}, + {0xda38bffa1d16cdd6, "SystemNative_SetLingerOption", nullptr}, + {0xda4898a26933f73d, "AndroidCryptoNative_DsaVerify", nullptr}, + {0xda6b3192974ca60e, "SystemNative_Open", nullptr}, + {0xdab5eb45815daabc, "SystemNative_GetAtOutOfBandMark", nullptr}, + {0xdae32aac0c0d305c, "SystemNative_ReadProcessStatusInfo", nullptr}, + {0xdbb4752ed23670f0, "AndroidCryptoNative_DesCbc", nullptr}, + {0xdbee22594fa8c585, "SystemNative_CreateAutoreleasePool", nullptr}, + {0xdc51159ffe70b0e0, "BrotliDecoderVersion", nullptr}, + {0xdc780005b0d39711, "AndroidCryptoNative_X509StoreGetPrivateKeyEntry", nullptr}, + {0xdd4c03f06ce96e04, "AndroidCryptoNative_RsaDestroy", nullptr}, + {0xdde06993f87d6ffc, "AndroidCryptoNative_Aes128Cfb128", nullptr}, + {0xde1e22dd097f799c, "AndroidCryptoNative_CipherSetNonceLength", nullptr}, + {0xde259001bf54e6f1, "AndroidCryptoNative_SSLStreamIsLocalCertificateUsed", nullptr}, + {0xdec5c7544d2c8cb1, "AndroidCryptoNative_GetDsaParameters", nullptr}, + {0xdf650444c8af0763, "SystemNative_FcntlGetIsNonBlocking", nullptr}, + {0xdfede2defd776f7e, "AndroidCryptoNative_X509ChainSetCustomTrustStore", nullptr}, + {0xe059239741e0011a, "AndroidCryptoNative_EcKeyCreateByKeyParameters", nullptr}, + {0xe072da8f2d921f53, "GlobalizationNative_GetDefaultLocaleName", nullptr}, + {0xe0a170d2b947a8fc, "SystemNative_SendMessage", nullptr}, + {0xe0a601fd89d9b279, "SystemNative_SetErrNo", nullptr}, + {0xe0f34ce89fd38aef, "AndroidCryptoNative_RsaPublicEncrypt", nullptr}, + {0xe1930d112ce74c9e, "SystemNative_TryGetUInt32OSThreadId", nullptr}, + {0xe20c29fb8b19da7b, "SystemNative_Listen", nullptr}, + {0xe36a157177b2db08, "SystemNative_GetNonCryptographicallySecureRandomBytes", nullptr}, + {0xe44f737a5bebdd90, "SystemNative_SetIPv4Address", nullptr}, + {0xe582a4a60bb74c35, "SystemNative_GetProcAddress", nullptr}, + {0xe604fca300068c0c, "AndroidCryptoNative_CipherCtxSetPadding", nullptr}, + {0xe6838f2add787bfe, "SystemNative_FreeLibrary", nullptr}, + {0xe73aeaf9e3a10343, "SystemNative_PWrite", nullptr}, + {0xe78ff100d1d73d99, "SystemNative_SetReceiveTimeout", nullptr}, + {0xe853ecfe4d402ed0, "SystemNative_Poll", nullptr}, + {0xea21aa1f2b2a671c, "GlobalizationNative_LastIndexOf", nullptr}, + {0xea5e6653389b924a, "CompressionNative_DeflateInit2_", nullptr}, + {0xea61d6c040267b2d, "BrotliSetDictionaryData", nullptr}, + {0xeaafb7963ceb9bf4, "SystemNative_GetTcpGlobalStatistics", nullptr}, + {0xeab45239fb3f138d, "AndroidCryptoNative_GetBigNumBytes", nullptr}, + {0xec67e4076662c2de, "SystemNative_GetDefaultSearchOrderPseudoHandle", nullptr}, + {0xee4dd111dc8d98f3, "GlobalizationNative_GetJapaneseEraStartDate", nullptr}, + {0xef71ee101b3ece96, "SystemNative_GetIcmpv6GlobalStatistics", nullptr}, + {0xeff5d014640ae969, "AndroidCryptoNative_DeleteGlobalReference", nullptr}, + {0xf0045895a9043221, "SystemNative_SearchPath_TempDirectory", nullptr}, + {0xf0658a22dd5ede19, "SystemNative_SNPrintF_1I", nullptr}, + {0xf0ec052da6c5fa70, "SystemNative_EnumerateGatewayAddressesForInterface", nullptr}, + {0xf1577384f409ea85, "AndroidCryptoNative_BigNumToBinary", nullptr}, + {0xf2c7fa39bf166188, "SystemNative_Free", nullptr}, + {0xf2d074e0aeca51ce, "GlobalizationNative_GetLocales", nullptr}, + {0xf3693f3cadb9b6f4, "GlobalizationNative_EnumCalendarInfo", nullptr}, + {0xf38b47e43f352491, "SystemNative_GetUdpGlobalStatistics", nullptr}, + {0xf432f105a045b088, "CryptoNative_ErrClearError", nullptr}, + {0xf4dea312f71c5ff2, "AndroidCryptoNative_Aes128Ecb", nullptr}, + {0xf4f5526ddc32beac, "CryptoNative_HmacDestroy", nullptr}, + {0xf57f81262f07542c, "AndroidCryptoNative_Des3Ecb", nullptr}, + {0xf63fa2bfce5c4f80, "GlobalizationNative_GetLocaleInfoGroupingSizes", nullptr}, + {0xf6ede5d5d8729315, "SystemNative_WaitIdAnyExitedNoHangNoWait", nullptr}, + {0xf75d4fdd6e749a84, "BrotliTransformDictionaryWord", nullptr}, + {0xf7b334768844b502, "AndroidCryptoNative_X509StoreContainsCertificate", nullptr}, + {0xf85b8ffeba9b06c1, "AndroidCryptoNative_X509StoreEnumerateTrustedCertificates", nullptr}, + {0xf870179a8d8d1872, "SystemNative_PosixFAdvise", nullptr}, + {0xf8c983dd21ef9fe6, "SystemNative_GetPid", nullptr}, + {0xf96bc1e7e15e69f2, "AndroidCryptoNative_CipherUpdate", nullptr}, + {0xf970881d4fa83e07, "AndroidCryptoNative_CipherCreate", nullptr}, + {0xf9c3d216226b3355, "AndroidCryptoNative_CipherSetTagLength", nullptr}, + {0xf9dea6e72f1fffc9, "CryptoNative_EvpMdCtxCreate", nullptr}, + {0xfa21f0a127c9dce9, "GlobalizationNative_ChangeCaseInvariant", nullptr}, + {0xfa2669c25616a8ff, "AndroidCryptoNative_X509IsKeyStorePrivateKeyEntry", nullptr}, + {0xfa26b86cedf66721, "SystemNative_Sysctl", nullptr}, + {0xfaa7766eaa2c54a5, "AndroidCryptoNative_DecodeRsaSubjectPublicKeyInfo", nullptr}, + {0xfacf02f439426705, "GlobalizationNative_CloseSortHandle", nullptr}, + {0xfb3e394cc613f202, "SystemNative_GetPeerName", nullptr}, + {0xfbb57319454b1074, "SystemNative_GetSpaceInfoForMountPoint", nullptr}, + {0xfc0bad2b1528000f, "AndroidCryptoNative_RsaVerificationPrimitive", nullptr}, + {0xfcdeea476953780c, "AndroidCryptoNative_Aes192Cfb128", nullptr}, + {0xfd2cdd99f11de76c, "AndroidCryptoNative_EcKeyGetSize", nullptr}, + {0xfd4f2784ec1c98aa, "AndroidCryptoNative_SSLStreamRequestClientAuthentication", nullptr}, + {0xfe3dd06281f7cd1f, "AndroidCryptoNative_SSLStreamInitialize", nullptr}, + {0xff28b3bec4f32a2c, "SystemNative_GetFileSystemType", nullptr}, + {0xff9b8d95b0e209fb, "BrotliEncoderHasMoreOutput", nullptr}, + {0xffce9341c40b2b73, "BrotliDecoderDecompress", nullptr}, + }}; + + +constexpr hash_t java_interop_library_hash = 0x54568ec36068e6b6; +constexpr hash_t xa_internal_api_library_hash = 0x43fd1b21148361b2; +constexpr hash_t system_native_library_hash = 0x4cd7bd0032e920e1; +constexpr hash_t system_io_compression_native_library_hash = 0x9190f4cb761b1d3c; +constexpr hash_t system_security_cryptography_native_android_library_hash = 0x1848c0093f0afd8; +constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; +#else + //32-bit internal p/invoke table + std::array internal_pinvokes {{ + {0xb02468aa, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, + {0xbe8d7701, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, + }}; + + //32-bit DotNet p/invoke table + std::array dotnet_pinvokes {{ + {0xaf6b1c, "AndroidCryptoNative_RsaPrivateDecrypt", nullptr}, + {0x1733089, "SystemNative_SetTerminalInvalidationHandler", nullptr}, + {0x1dd1f00, "AndroidCryptoNative_Aes192Cfb8", nullptr}, + {0x23a0578, "AndroidCryptoNative_NewGlobalReference", nullptr}, + {0x2f05496, "SystemNative_GetPeerName", nullptr}, + {0x3295077, "SystemNative_MapTcpState", nullptr}, + {0x3d9bc5f, "SystemNative_Unlink", nullptr}, + {0x3e12cb4, "SystemNative_INotifyInit", nullptr}, + {0x5b0fb1d, "SystemNative_InitializeConsoleBeforeRead", nullptr}, + {0x80f30b4, "BrotliDecoderTakeOutput", nullptr}, + {0x84ccf89, "SystemNative_MSync", nullptr}, + {0x8c636a2, "SystemNative_FcntlSetPipeSz", nullptr}, + {0x8de5b3d, "SystemNative_GetSid", nullptr}, + {0x92bf2d9, "AndroidCryptoNative_EcKeyGetSize", nullptr}, + {0xaa46d20, "SystemNative_SNPrintF", nullptr}, + {0xaa7c86e, "SystemNative_Exit", nullptr}, + {0xb6a80bd, "SystemNative_SetAddressFamily", nullptr}, + {0xbdd984d, "SystemNative_SetWindowSize", nullptr}, + {0xcc59904, "CryptoNative_HmacDestroy", nullptr}, + {0xd5ca844, "SystemNative_CreateSocketEventPort", nullptr}, + {0xd98d741, "SystemNative_Kill", nullptr}, + {0xdfe3e26, "SystemNative_Connectx", nullptr}, + {0xfc48476, "SystemNative_GetNonCryptographicallySecureRandomBytes", nullptr}, + {0x10d108c9, "SystemNative_FreeHostEntry", nullptr}, + {0x1165644f, "SystemNative_GetOSArchitecture", nullptr}, + {0x11778651, "SystemNative_ConfigureTerminalForChildProcess", nullptr}, + {0x1178ebdd, "CryptoNative_EvpDigestFinalEx", nullptr}, + {0x11a2796d, "SystemNative_GetTcpGlobalStatistics", nullptr}, + {0x11d9981e, "SystemNative_MProtect", nullptr}, + {0x12105897, "GlobalizationNative_NormalizeString", nullptr}, + {0x12b01cc9, "GlobalizationNative_IsNormalized", nullptr}, + {0x12fdf5c3, "SystemNative_ConvertErrorPlatformToPal", nullptr}, + {0x1348bf25, "AndroidCryptoNative_SSLStreamWrite", nullptr}, + {0x1376985b, "SystemNative_SetSockOpt", nullptr}, + {0x13925de2, "SystemNative_GetLingerOption", nullptr}, + {0x13f565a9, "SystemNative_GetControlMessageBufferSize", nullptr}, + {0x142a08a1, "SystemNative_PosixFAdvise", nullptr}, + {0x16d98313, "GlobalizationNative_IndexOf", nullptr}, + {0x17549123, "SystemNative_Connect", nullptr}, + {0x17a5d095, "AndroidCryptoNative_SSLStreamGetApplicationProtocol", nullptr}, + {0x17b96c39, "SystemNative_FreeSocketEventBuffer", nullptr}, + {0x1904820d, "SystemNative_GetHostEntryForName", nullptr}, + {0x19b6a696, "AndroidCryptoNative_X509DecodeCollection", nullptr}, + {0x1a302b28, "SystemNative_SchedSetAffinity", nullptr}, + {0x1aa4105d, "GlobalizationNative_GetSortKey", nullptr}, + {0x1ab1248e, "SystemNative_GetHostName", nullptr}, + {0x1bf277c4, "SystemNative_WaitForSocketEvents", nullptr}, + {0x1c4778bf, "SystemNative_AlignedFree", nullptr}, + {0x1cb466df, "AndroidCryptoNative_RsaGenerateKeyEx", nullptr}, + {0x1cf7b52c, "SystemNative_MAdvise", nullptr}, + {0x1eb6eaaa, "CryptoNative_GetRandomBytes", nullptr}, + {0x1ebc63c1, "AndroidCryptoNative_X509ChainDestroyContext", nullptr}, + {0x1f186646, "AndroidCryptoNative_CipherSetKeyAndIV", nullptr}, + {0x1f1cd573, "AndroidCryptoNative_Des3Cfb64", nullptr}, + {0x1f998744, "AndroidCryptoNative_Aes128Cfb128", nullptr}, + {0x1fdcd1e0, "CryptoNative_ErrPeekError", nullptr}, + {0x212e38c4, "SystemNative_GetUdpGlobalStatistics", nullptr}, + {0x218fa94a, "AndroidCryptoNative_X509StoreDeleteEntry", nullptr}, + {0x22011e2b, "SystemNative_SetLingerOption", nullptr}, + {0x224ebd71, "SystemNative_Listen", nullptr}, + {0x2253b591, "BrotliGetTransforms", nullptr}, + {0x226eec4d, "SystemNative_Abort", nullptr}, + {0x229f73d4, "AndroidCryptoNative_RsaUpRef", nullptr}, + {0x22bbb587, "AndroidCryptoNative_SSLStreamGetPeerCertificate", nullptr}, + {0x2304e65b, "SystemNative_SetRLimit", nullptr}, + {0x23cfcfb0, "BrotliTransformDictionaryWord", nullptr}, + {0x260a3e8d, "CompressionNative_DeflateInit2_", nullptr}, + {0x289b5430, "SystemNative_Log", nullptr}, + {0x28d95a99, "SystemNative_CanGetHiddenFlag", nullptr}, + {0x28f3db4b, "SystemNative_ShmUnlink", nullptr}, + {0x2af6aa40, "SystemNative_Access", nullptr}, + {0x2b117055, "BrotliDecoderDecompress", nullptr}, + {0x2b7293c5, "SystemNative_GetTimestamp", nullptr}, + {0x2b747a9c, "SystemNative_MkNod", nullptr}, + {0x2bc9ff5e, "AndroidCryptoNative_SSLStreamGetProtocol", nullptr}, + {0x2c4415fd, "AndroidCryptoNative_AeadCipherFinalEx", nullptr}, + {0x2c467430, "AndroidCryptoNative_GetECCurveParameters", nullptr}, + {0x2d21ad97, "SystemNative_GetReadDirRBufferSize", nullptr}, + {0x2d6e4a1c, "AndroidCryptoNative_X509StoreRemoveCertificate", nullptr}, + {0x2e66f31b, "BrotliDecoderDestroyInstance", nullptr}, + {0x2eb28fb6, "SystemNative_GetIPv4Address", nullptr}, + {0x2f7d80dd, "GlobalizationNative_WindowsIdToIanaId", nullptr}, + {0x2ff73621, "CryptoNative_ErrReasonErrorString", nullptr}, + {0x30af09b7, "AndroidCryptoNative_DecodeRsaSubjectPublicKeyInfo", nullptr}, + {0x31120969, "SystemNative_Malloc", nullptr}, + {0x3374b950, "SystemNative_GetLoadLibraryError", nullptr}, + {0x34867c2f, "SystemNative_TryGetUInt32OSThreadId", nullptr}, + {0x349c5a8f, "SystemNative_GetNetworkInterfaces", nullptr}, + {0x354aa58f, "AndroidCryptoNative_DsaKeyCreateByExplicitParameters", nullptr}, + {0x363c0010, "CryptoNative_EvpDigestUpdate", nullptr}, + {0x367eee31, "AndroidCryptoNative_SSLStreamIsLocalCertificateUsed", nullptr}, + {0x38406fa3, "GlobalizationNative_ChangeCaseInvariant", nullptr}, + {0x38575bc5, "SystemNative_GetUnixRelease", nullptr}, + {0x388a31d4, "SystemNative_PathConf", nullptr}, + {0x3a238b9f, "AndroidCryptoNative_RsaVerificationPrimitive", nullptr}, + {0x3a861d34, "SystemNative_GetNativeIPInterfaceStatistics", nullptr}, + {0x3af56a10, "AndroidCryptoNative_RsaSize", nullptr}, + {0x3b286185, "GlobalizationNative_ChangeCaseTurkish", nullptr}, + {0x3bf3d465, "SystemNative_GetIPv6MulticastOption", nullptr}, + {0x3cb49aae, "SystemNative_GetPwNamR", nullptr}, + {0x3d150bdf, "AndroidCryptoNative_Aes128Ecb", nullptr}, + {0x3d823979, "GlobalizationNative_ToUnicode", nullptr}, + {0x3da52690, "SystemNative_FcntlCanGetSetPipeSz", nullptr}, + {0x3de52faf, "AndroidCryptoNative_CipherUpdateAAD", nullptr}, + {0x3df8d649, "SystemNative_SetDelayedSigChildConsoleConfigurationHandler", nullptr}, + {0x3e175e7c, "AndroidCryptoNative_Aes256Cfb128", nullptr}, + {0x3e273961, "SystemNative_StrErrorR", nullptr}, + {0x3e48f022, "SystemNative_GetMaximumAddressSize", nullptr}, + {0x3e778b38, "BrotliDecoderVersion", nullptr}, + {0x3ea31c40, "SystemNative_GetAddressFamily", nullptr}, + {0x3efdb5a0, "SystemNative_SendMessage", nullptr}, + {0x3f47618f, "CryptoNative_EnsureOpenSslInitialized", nullptr}, + {0x3f793993, "SystemNative_LowLevelMonitor_Signal_Release", nullptr}, + {0x40b0026c, "CompressionNative_DeflateEnd", nullptr}, + {0x40e64bdd, "CryptoNative_ErrClearError", nullptr}, + {0x413b9801, "SystemNative_Read", nullptr}, + {0x41818c1d, "SystemNative_GetPriority", nullptr}, + {0x41cf0c16, "AndroidCryptoNative_CipherCreate", nullptr}, + {0x42955366, "SystemNative_Disconnect", nullptr}, + {0x42afcfbb, "AndroidCryptoNative_CipherCreatePartial", nullptr}, + {0x430352b3, "SystemNative_GetNameInfo", nullptr}, + {0x43f6cea1, "AndroidCryptoNative_DesCfb8", nullptr}, + {0x4543d533, "AndroidCryptoNative_EcDsaVerify", nullptr}, + {0x45a00971, "GlobalizationNative_CloseSortHandle", nullptr}, + {0x45f09dca, "AndroidCryptoNative_CipherSetTagLength", nullptr}, + {0x46268e76, "GlobalizationNative_GetCalendarInfo", nullptr}, + {0x477f60cf, "SystemNative_OpenDir", nullptr}, + {0x47a82b4e, "SystemNative_AlignedRealloc", nullptr}, + {0x48c17c9b, "SystemNative_Sysctl", nullptr}, + {0x493888ee, "CompressionNative_Crc32", nullptr}, + {0x494ef6d4, "SystemNative_GetIPv4MulticastOption", nullptr}, + {0x496f1885, "SystemNative_GetSocketErrorOption", nullptr}, + {0x49c2af32, "SystemNative_GetBootTimeTicks", nullptr}, + {0x49c81782, "SystemNative_MkDir", nullptr}, + {0x49f60a0f, "GlobalizationNative_GetLocales", nullptr}, + {0x4a4ef46f, "SystemNative_FcntlGetFD", nullptr}, + {0x4a98a396, "GlobalizationNative_GetLocaleInfoInt", nullptr}, + {0x4b78d330, "CryptoNative_HmacCurrent", nullptr}, + {0x4c2eae6c, "GlobalizationNative_EnumCalendarInfo", nullptr}, + {0x4c6d50ba, "SystemNative_GetIPv4GlobalStatistics", nullptr}, + {0x4ca38207, "AndroidCryptoNative_X509StoreEnumerateTrustedCertificates", nullptr}, + {0x4cb997ae, "BrotliEncoderCompress", nullptr}, + {0x4d1a35d1, "SystemNative_LowLevelMonitor_Release", nullptr}, + {0x4d75bb15, "SystemNative_WaitIdAnyExitedNoHangNoWait", nullptr}, + {0x4dbf0c74, "SystemNative_CreateSocketEventBuffer", nullptr}, + {0x4e4d4f2a, "SystemNative_SetIPv6Address", nullptr}, + {0x4f6011da, "SystemNative_GetPort", nullptr}, + {0x4f6c3726, "SystemNative_FcntlGetIsNonBlocking", nullptr}, + {0x50e88639, "CryptoNative_HmacUpdate", nullptr}, + {0x514e739b, "AndroidCryptoNative_EcKeyCreateByExplicitParameters", nullptr}, + {0x52590509, "AndroidCryptoNative_Aes128Cbc", nullptr}, + {0x526c9f90, "SystemNative_GetNumRoutes", nullptr}, + {0x52896a81, "SystemNative_ChMod", nullptr}, + {0x538521c9, "GlobalizationNative_IanaIdToWindowsId", nullptr}, + {0x54d6c29d, "GlobalizationNative_GetJapaneseEraStartDate", nullptr}, + {0x5600bd0d, "AndroidCryptoNative_SSLStreamCreate", nullptr}, + {0x561fb6ff, "SystemNative_FStat", nullptr}, + {0x564f6794, "AndroidCryptoNative_Pbkdf2", nullptr}, + {0x56993aa9, "SystemNative_SetKeypadXmit", nullptr}, + {0x57bdcc46, "SystemNative_Open", nullptr}, + {0x581adfc6, "SystemNative_GetSignalForBreak", nullptr}, + {0x5906e1ba, "SystemNative_Close", nullptr}, + {0x591c5746, "AndroidCryptoNative_EcKeyUpRef", nullptr}, + {0x59840533, "AndroidCryptoNative_X509Decode", nullptr}, + {0x5989ad17, "SystemNative_GetIcmpv4GlobalStatistics", nullptr}, + {0x599921d3, "SystemNative_SysConf", nullptr}, + {0x59b67f4d, "AndroidCryptoNative_SSLGetSupportedProtocols", nullptr}, + {0x59e712d5, "SystemNative_MkdTemp", nullptr}, + {0x5a492732, "SystemNative_FcntlSetFD", nullptr}, + {0x5ccc38dd, "AndroidCryptoNative_SSLStreamGetPeerCertificates", nullptr}, + {0x5e9ef1a2, "SystemNative_GetAtOutOfBandMark", nullptr}, + {0x5eb4f827, "SystemNative_LockFileRegion", nullptr}, + {0x5ed67634, "SystemNative_GetPwUidR", nullptr}, + {0x5efc6409, "SystemNative_ReceiveSocketError", nullptr}, + {0x5f706f52, "AndroidCryptoNative_RsaSignPrimitive", nullptr}, + {0x5fc58bed, "SystemNative_GetEstimatedTcpConnectionCount", nullptr}, + {0x60571eb9, "AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration", nullptr}, + {0x6068baa0, "AndroidCryptoNative_GetRsaParameters", nullptr}, + {0x608ee1a5, "SystemNative_Calloc", nullptr}, + {0x60c353e5, "SystemNative_SetPosixSignalHandler", nullptr}, + {0x613c0080, "AndroidCryptoNative_Aes192Ccm", nullptr}, + {0x626db703, "SystemNative_LStat", nullptr}, + {0x6288dd9a, "SystemNative_SetSignalForBreak", nullptr}, + {0x62a36e75, "AndroidCryptoNative_X509ChainGetErrorCount", nullptr}, + {0x639b2b1d, "AndroidCryptoNative_DsaVerify", nullptr}, + {0x6436999d, "AndroidCryptoNative_SSLStreamRead", nullptr}, + {0x6441bc65, "CryptoNative_EvpSha256", nullptr}, + {0x64f12e5b, "BrotliDecoderIsFinished", nullptr}, + {0x661c5218, "SystemNative_GetDomainName", nullptr}, + {0x6661a841, "BrotliDecoderDecompressStream", nullptr}, + {0x66b5bf9d, "GlobalizationNative_IsPredefinedLocale", nullptr}, + {0x674bdf7f, "SystemNative_DisablePosixSignalHandling", nullptr}, + {0x679dd832, "SystemNative_SetPort", nullptr}, + {0x679f9b4e, "SystemNative_FcntlGetPipeSz", nullptr}, + {0x67de0842, "SystemNative_Dup", nullptr}, + {0x687726ff, "AndroidCryptoNative_EcKeyGetCurveName", nullptr}, + {0x68bdc398, "SystemNative_INotifyAddWatch", nullptr}, + {0x68c949a0, "AndroidCryptoNative_X509GetContentType", nullptr}, + {0x68f9f52f, "AndroidCryptoNative_CipherIsSupported", nullptr}, + {0x6907c8eb, "BrotliEncoderSetParameter", nullptr}, + {0x6adb646e, "SystemNative_ReadDirR", nullptr}, + {0x6b5343a0, "SystemNative_SetErrNo", nullptr}, + {0x6bbd3d10, "SystemNative_GetRLimit", nullptr}, + {0x6be1e33d, "SystemNative_EnumerateInterfaceAddresses", nullptr}, + {0x6cda2cf8, "SystemNative_SetSendTimeout", nullptr}, + {0x6d48392a, "SystemNative_Stat", nullptr}, + {0x6ece5fe6, "SystemNative_GetPid", nullptr}, + {0x6ef4e421, "AndroidCryptoNative_CipherDestroy", nullptr}, + {0x6f18d737, "GlobalizationNative_InitICUFunctions", nullptr}, + {0x6f695cb8, "SystemNative_RmDir", nullptr}, + {0x6fa886b1, "SystemNative_GetSockName", nullptr}, + {0x6fc36e5f, "GlobalizationNative_StartsWith", nullptr}, + {0x708e7911, "SystemNative_SetIPv4Address", nullptr}, + {0x70d4f7e6, "SystemNative_GetActiveTcpConnectionInfos", nullptr}, + {0x70e91ddd, "SystemNative_FChMod", nullptr}, + {0x71698a7f, "SystemNative_GetDomainSocketSizes", nullptr}, + {0x7243c4b4, "AndroidCryptoNative_Des3Cfb8", nullptr}, + {0x758dd6aa, "SystemNative_GetTimeZoneData", nullptr}, + {0x759f5b1e, "AndroidCryptoNative_Aes256Cfb8", nullptr}, + {0x75b11f61, "BrotliDecoderGetErrorCode", nullptr}, + {0x76e97b2e, "SystemNative_Rename", nullptr}, + {0x78c1eb52, "AndroidCryptoNative_Des3Ecb", nullptr}, + {0x7a0529c1, "SystemNative_InitializeTerminalAndSignalHandling", nullptr}, + {0x7a4012d2, "GlobalizationNative_GetICUVersion", nullptr}, + {0x7aa30494, "Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate", nullptr}, + {0x7ad3b820, "AndroidCryptoNative_Aes192Cfb128", nullptr}, + {0x7cb19137, "SystemNative_GetIcmpv6GlobalStatistics", nullptr}, + {0x7d0c477d, "CryptoNative_ErrPeekLastError", nullptr}, + {0x7d2bb98a, "SystemNative_MksTemps", nullptr}, + {0x7de70253, "SystemNative_ConvertErrorPalToPlatform", nullptr}, + {0x7e882ae5, "BrotliEncoderIsFinished", nullptr}, + {0x7e9a677b, "GlobalizationNative_GetSortVersion", nullptr}, + {0x7f5d9e25, "SystemNative_MUnmap", nullptr}, + {0x80d5027e, "CryptoNative_EvpMdCtxCopyEx", nullptr}, + {0x80deced4, "SystemNative_CreateAutoreleasePool", nullptr}, + {0x81a5efac, "SystemNative_SetEUid", nullptr}, + {0x82484cbf, "CryptoNative_EvpDigestOneShot", nullptr}, + {0x8289a6f7, "BrotliDefaultFreeFunc", nullptr}, + {0x83dad9bf, "SystemNative_Pipe", nullptr}, + {0x83db1b72, "CryptoNative_EvpDigestCurrent", nullptr}, + {0x84662605, "CompressionNative_Deflate", nullptr}, + {0x8526c9e8, "SystemNative_SetRawSockOpt", nullptr}, + {0x8574b133, "AndroidCryptoNative_Aes192Ecb", nullptr}, + {0x85abed93, "GlobalizationNative_GetCalendars", nullptr}, + {0x8808879d, "AndroidCryptoNative_X509StoreGetPrivateKeyEntry", nullptr}, + {0x88a7558d, "SystemNative_GetDefaultSearchOrderPseudoHandle", nullptr}, + {0x8ba80ef4, "GlobalizationNative_InitOrdinalCasingPage", nullptr}, + {0x8bdaf06c, "SystemNative_GetWindowSize", nullptr}, + {0x8bfcd7ba, "CompressionNative_Inflate", nullptr}, + {0x8d38b733, "SystemNative_LSeek", nullptr}, + {0x8f4e59f1, "SystemNative_ReadStdin", nullptr}, + {0x8f628a8d, "GlobalizationNative_CompareString", nullptr}, + {0x909e12ee, "SystemNative_SearchPath", nullptr}, + {0x910b7740, "SystemNative_GetFormatInfoForMountPoint", nullptr}, + {0x913a3d68, "SystemNative_GetDeviceIdentifiers", nullptr}, + {0x9216d936, "SystemNative_GetGroupName", nullptr}, + {0x94477030, "AndroidCryptoNative_Aes256Ccm", nullptr}, + {0x95e99740, "AndroidCryptoNative_SSLStreamInitialize", nullptr}, + {0x960d4fc0, "SystemNative_GetDefaultTimeZone", nullptr}, + {0x966f54af, "CryptoNative_EvpSha384", nullptr}, + {0x96912459, "AndroidCryptoNative_X509GetCertificateForPrivateKeyEntry", nullptr}, + {0x9787b4b4, "CryptoNative_EvpMdSize", nullptr}, + {0x98105435, "SystemNative_GetIPv6Address", nullptr}, + {0x984edaf1, "AndroidCryptoNative_RsaDestroy", nullptr}, + {0x9852b0fa, "SystemNative_INotifyRemoveWatch", nullptr}, + {0x98954db8, "AndroidCryptoNative_X509StoreOpenDefault", nullptr}, + {0x98ca7f1c, "SystemNative_ChDir", nullptr}, + {0x990163b4, "SystemNative_Receive", nullptr}, + {0x996952b3, "AndroidCryptoNative_CipherFinalEx", nullptr}, + {0x9a005080, "SystemNative_Bind", nullptr}, + {0x9a84ffd3, "AndroidCryptoNative_ChaCha20Poly1305", nullptr}, + {0x9abfce84, "SystemNative_GetEnviron", nullptr}, + {0x9bda7eb1, "SystemNative_ReadProcessStatusInfo", nullptr}, + {0x9cd6cae8, "AndroidCryptoNative_SSLStreamRelease", nullptr}, + {0x9d102d58, "CompressionNative_InflateEnd", nullptr}, + {0x9d2f90cf, "GlobalizationNative_GetLatestJapaneseEra", nullptr}, + {0x9d7f4af6, "SystemNative_ReceiveMessage", nullptr}, + {0x9dc3baed, "SystemNative_LowLevelMonitor_Destroy", nullptr}, + {0x9e366e9c, "SystemNative_InterfaceNameToIndex", nullptr}, + {0x9e717f20, "SystemNative_LChflagsCanSetHiddenFlag", nullptr}, + {0x9f47b32d, "SystemNative_ShmOpen", nullptr}, + {0x9feb81cb, "SystemNative_SNPrintF_1I", nullptr}, + {0xa0db1858, "SystemNative_GetEnv", nullptr}, + {0xa1295a9f, "SystemNative_MkFifo", nullptr}, + {0xa1bec9da, "SystemNative_LogError", nullptr}, + {0xa1d774fc, "BrotliEncoderHasMoreOutput", nullptr}, + {0xa2430b33, "SystemNative_SearchPath_TempDirectory", nullptr}, + {0xa25daa0e, "BrotliSetDictionaryData", nullptr}, + {0xa2d2f390, "SystemNative_TryChangeSocketEventRegistration", nullptr}, + {0xa39be756, "GlobalizationNative_LoadICU", nullptr}, + {0xa4636764, "AndroidCryptoNative_X509ChainCreateContext", nullptr}, + {0xa477c74e, "SystemNative_TryGetIPPacketInformation", nullptr}, + {0xa635da0f, "AndroidCryptoNative_SSLStreamShutdown", nullptr}, + {0xa691d151, "AndroidCryptoNative_Aes192Cbc", nullptr}, + {0xa72ce322, "AndroidCryptoNative_DeleteGlobalReference", nullptr}, + {0xa8074d4c, "GlobalizationNative_GetSortHandle", nullptr}, + {0xa826eabe, "SystemNative_FcntlSetIsNonBlocking", nullptr}, + {0xa829138a, "SystemNative_GetProcessPath", nullptr}, + {0xa8701bcf, "AndroidCryptoNative_SSLStreamRequestClientAuthentication", nullptr}, + {0xa8da7ba1, "BrotliEncoderVersion", nullptr}, + {0xa936bc40, "AndroidCryptoNative_EcDsaSize", nullptr}, + {0xa9c29be5, "SystemNative_SetIPv6MulticastOption", nullptr}, + {0xa9c84a4a, "AndroidCryptoNative_X509ExportPkcs7", nullptr}, + {0xaa13ec2b, "GlobalizationNative_GetLocaleInfoGroupingSizes", nullptr}, + {0xaa2f32ad, "SystemNative_FTruncate", nullptr}, + {0xab37a684, "CryptoNative_HmacCreate", nullptr}, + {0xab3d1641, "AndroidCryptoNative_DesEcb", nullptr}, + {0xabe6739f, "BrotliGetDictionary", nullptr}, + {0xacc26fa4, "AndroidCryptoNative_SSLStreamCreateWithCertificates", nullptr}, + {0xacc28460, "SystemNative_GetProcAddress", nullptr}, + {0xad7fbde5, "SystemNative_FUTimens", nullptr}, + {0xae443204, "SystemNative_GetSockOpt", nullptr}, + {0xae449ad1, "BrotliDecoderIsUsed", nullptr}, + {0xae8752e4, "GlobalizationNative_ToAscii", nullptr}, + {0xafb02e71, "BrotliEncoderMaxCompressedSize", nullptr}, + {0xb01e9c27, "AndroidCryptoNative_SSLStreamSetEnabledProtocols", nullptr}, + {0xb030a893, "SystemNative_LowLevelMonitor_Acquire", nullptr}, + {0xb0e270a0, "BrotliEncoderDestroyInstance", nullptr}, + {0xb22a12be, "BrotliEncoderCreateInstance", nullptr}, + {0xb26f05b6, "SystemNative_PWrite", nullptr}, + {0xb2965ccd, "CryptoNative_GetMaxMdSize", nullptr}, + {0xb2985645, "AndroidCryptoNative_X509StoreEnumerateCertificates", nullptr}, + {0xb4110b14, "AndroidCryptoNative_DsaGenerateKey", nullptr}, + {0xb427959c, "SystemNative_FLock", nullptr}, + {0xb439ebdb, "AndroidCryptoNative_RegisterRemoteCertificateValidationCallback", nullptr}, + {0xb444f04a, "SystemNative_Accept", nullptr}, + {0xb448a24a, "SystemNative_SymLink", nullptr}, + {0xb4e5c37d, "SystemNative_UTimensat", nullptr}, + {0xb584e8fb, "GlobalizationNative_GetTimeZoneDisplayName", nullptr}, + {0xb5a5754a, "SystemNative_UninitializeConsoleAfterRead", nullptr}, + {0xb5db6a51, "SystemNative_PWriteV", nullptr}, + {0xb628f475, "SystemNative_GetBytesAvailable", nullptr}, + {0xb7041ffa, "SystemNative_GetControlCharacters", nullptr}, + {0xb7cc3cd1, "AndroidCryptoNative_DesCbc", nullptr}, + {0xb7ebdf2c, "AndroidCryptoNative_X509IsKeyStorePrivateKeyEntry", nullptr}, + {0xb80f233c, "SystemNative_FSync", nullptr}, + {0xb84914f1, "SystemNative_EnumerateGatewayAddressesForInterface", nullptr}, + {0xb862b34e, "AndroidCryptoNative_CipherSetNonceLength", nullptr}, + {0xb884b933, "SystemNative_StdinReady", nullptr}, + {0xb96c2133, "SystemNative_GetErrNo", nullptr}, + {0xb97add7d, "SystemNative_CreateNetworkChangeListenerSocket", nullptr}, + {0xb9e6cb2c, "SystemNative_RealPath", nullptr}, + {0xba284ef4, "CryptoNative_EvpSha1", nullptr}, + {0xbb06f5e1, "AndroidCryptoNative_Aes192Gcm", nullptr}, + {0xbb25ff40, "AndroidCryptoNative_SSLStreamSetTargetHost", nullptr}, + {0xbb2ca4f3, "SystemNative_Link", nullptr}, + {0xbb92466f, "SystemNative_AlignedAlloc", nullptr}, + {0xbd658356, "CryptoNative_ErrErrorStringN", nullptr}, + {0xbdbf2140, "SystemNative_SchedGetAffinity", nullptr}, + {0xbec8a3f2, "SystemNative_FChflags", nullptr}, + {0xbf4eeb78, "AndroidCryptoNative_GetBigNumBytes", nullptr}, + {0xbf9766c3, "AndroidCryptoNative_SSLStreamHandshake", nullptr}, + {0xbfa0ce53, "SystemNative_GetPlatformSignalNumber", nullptr}, + {0xbfaad12d, "BrotliDecoderSetParameter", nullptr}, + {0xc090b1d3, "CryptoNative_EvpSha512", nullptr}, + {0xc0d66913, "SystemNative_GetUnixVersion", nullptr}, + {0xc11dec94, "SystemNative_FAllocate", nullptr}, + {0xc1243135, "AndroidCryptoNative_Aes128Gcm", nullptr}, + {0xc1e4e6f6, "AndroidCryptoNative_BigNumToBinary", nullptr}, + {0xc25ffc33, "BrotliEncoderCompressStream", nullptr}, + {0xc3812682, "AndroidCryptoNative_X509ChainGetErrors", nullptr}, + {0xc3dcc3a0, "AndroidCryptoNative_SetRsaParameters", nullptr}, + {0xc3e6ff56, "SystemNative_LowLevelMonitor_Create", nullptr}, + {0xc475f41c, "AndroidCryptoNative_X509StoreContainsCertificate", nullptr}, + {0xc4ac1723, "AndroidCryptoNative_Aes256Cbc", nullptr}, + {0xc55548f2, "SystemNative_HandleNonCanceledPosixSignal", nullptr}, + {0xc57b40fa, "SystemNative_LoadLibrary", nullptr}, + {0xc5a83c28, "AndroidCryptoNative_SSLStreamCreateWithKeyStorePrivateKeyEntry", nullptr}, + {0xc6d5929c, "SystemNative_LowLevelMonitor_TimedWait", nullptr}, + {0xc6f2fb9e, "AndroidCryptoNative_X509ChainSetCustomTrustStore", nullptr}, + {0xc717b16e, "CryptoNative_EvpMdCtxDestroy", nullptr}, + {0xc746b70c, "AndroidCryptoNative_DsaSign", nullptr}, + {0xc83527e0, "CryptoNative_HmacReset", nullptr}, + {0xc89ccd22, "SystemNative_SchedGetCpu", nullptr}, + {0xc8cce896, "SystemNative_GetSocketType", nullptr}, + {0xc8e06b20, "AndroidCryptoNative_X509ChainGetCertificates", nullptr}, + {0xc9b017c8, "AndroidCryptoNative_EcKeyCreateByOid", nullptr}, + {0xca4dad90, "GlobalizationNative_ChangeCase", nullptr}, + {0xca5aab33, "SystemNative_Sync", nullptr}, + {0xcb458400, "CryptoNative_ErrGetErrorAlloc", nullptr}, + {0xcb746e5c, "SystemNative_SetIPv4MulticastOption", nullptr}, + {0xcb85cd8e, "AndroidCryptoNative_EcdhDeriveKey", nullptr}, + {0xccc0dd15, "SystemNative_RegisterForSigChld", nullptr}, + {0xcdfb627d, "SystemNative_FreeLibrary", nullptr}, + {0xce91e293, "SystemNative_GetGroupList", nullptr}, + {0xcf0912c8, "GlobalizationNative_GetLocaleTimeFormat", nullptr}, + {0xcf9bcc75, "AndroidCryptoNative_Aes256Gcm", nullptr}, + {0xcfa9e6f1, "AndroidCryptoNative_GetDsaParameters", nullptr}, + {0xcff9b341, "SystemNative_GetSystemTimeAsTicks", nullptr}, + {0xd199e841, "SystemNative_GetEstimatedUdpListenerCount", nullptr}, + {0xd24d4849, "SystemNative_Socket", nullptr}, + {0xd298c3b3, "SystemNative_Write", nullptr}, + {0xd378ba49, "CryptoNative_EvpMd5", nullptr}, + {0xd473c64c, "SystemNative_SetReceiveTimeout", nullptr}, + {0xd4b91180, "SystemNative_ForkAndExecProcess", nullptr}, + {0xd6d7b4fb, "AndroidCryptoNative_X509ChainGetCertificateCount", nullptr}, + {0xd71d8c66, "AndroidCryptoNative_Aes256Ecb", nullptr}, + {0xd7ee326b, "AndroidCryptoNative_EcKeyDestroy", nullptr}, + {0xd818a523, "AndroidCryptoNative_CipherCtxSetPadding", nullptr}, + {0xd9458396, "BrotliDecoderCreateInstance", nullptr}, + {0xda040de4, "GlobalizationNative_EndsWith", nullptr}, + {0xdaaa19b2, "SystemNative_GetAllMountPoints", nullptr}, + {0xdac67152, "AndroidCryptoNative_X509StoreAddCertificate", nullptr}, + {0xdad29aeb, "AndroidCryptoNative_CipherUpdate", nullptr}, + {0xdaf0460a, "SystemNative_SendFile", nullptr}, + {0xdbbf4917, "AndroidCryptoNative_SSLStreamGetCipherSuite", nullptr}, + {0xdbdce4ef, "BrotliDefaultAllocFunc", nullptr}, + {0xdbe13a57, "SystemNative_GetCpuUtilization", nullptr}, + {0xdc3cbeec, "CryptoNative_HmacOneShot", nullptr}, + {0xdcaddb21, "AndroidCryptoNative_GetECKeyParameters", nullptr}, + {0xdd274c15, "AndroidCryptoNative_RsaPublicEncrypt", nullptr}, + {0xdd445632, "AndroidCryptoNative_X509ChainValidate", nullptr}, + {0xddd58443, "SystemNative_PReadV", nullptr}, + {0xdea9b9dc, "SystemNative_EnablePosixSignalHandling", nullptr}, + {0xdf0260d8, "GlobalizationNative_GetLocaleInfoString", nullptr}, + {0xdf4f1977, "AndroidCryptoNative_X509PublicKey", nullptr}, + {0xdf5d3dc8, "GlobalizationNative_GetDefaultLocaleName", nullptr}, + {0xdf80df75, "SystemNative_iOSSupportVersion", nullptr}, + {0xe121bac7, "SystemNative_GetPeerID", nullptr}, + {0xe169faa6, "AndroidCryptoNative_SSLStreamSetApplicationProtocols", nullptr}, + {0xe1b8b44f, "SystemNative_Send", nullptr}, + {0xe2a0d0de, "SystemNative_GetSpaceInfoForMountPoint", nullptr}, + {0xe4a78efb, "SystemNative_SetPriority", nullptr}, + {0xe4dba4f6, "SystemNative_GetCwd", nullptr}, + {0xe4f87d25, "AndroidCryptoNative_SSLStreamVerifyHostname", nullptr}, + {0xe50c82b4, "SystemNative_CreateThread", nullptr}, + {0xe58ed8fe, "SystemNative_PlatformSupportsDualModeIPv4PacketInfo", nullptr}, + {0xe5ef37b3, "AndroidCryptoNative_DsaSignatureFieldSize", nullptr}, + {0xe70a3634, "GlobalizationNative_GetLocaleName", nullptr}, + {0xe770cb3f, "SystemNative_CopyFile", nullptr}, + {0xe7a9a106, "CompressionNative_InflateInit2_", nullptr}, + {0xe7bd8dd1, "AndroidCryptoNative_EcKeyCreateByKeyParameters", nullptr}, + {0xe890cf58, "AndroidCryptoNative_EcDsaSign", nullptr}, + {0xe8b2ec8d, "BrotliDecoderErrorString", nullptr}, + {0xe972fbd9, "SystemNative_GetEGid", nullptr}, + {0xe9bc4e53, "SystemNative_SNPrintF_1S", nullptr}, + {0xea86f52f, "BrotliEncoderTakeOutput", nullptr}, + {0xeb0d0522, "SystemNative_LowLevelMonitor_Wait", nullptr}, + {0xebacbf92, "AndroidCryptoNative_Aes128Cfb8", nullptr}, + {0xec31140d, "BrotliDecoderHasMoreOutput", nullptr}, + {0xec51a1b4, "SystemNative_LChflags", nullptr}, + {0xed6cc182, "CryptoNative_EvpMdCtxCreate", nullptr}, + {0xee74a5ad, "AndroidCryptoNative_DsaSizeP", nullptr}, + {0xef48c2eb, "CryptoNative_EvpDigestReset", nullptr}, + {0xef5890c7, "AndroidCryptoNative_Des3Cbc", nullptr}, + {0xefb38c9f, "SystemNative_Poll", nullptr}, + {0xefd277f7, "CryptoNative_HmacFinal", nullptr}, + {0xf06b440b, "AndroidCryptoNative_DsaSizeSignature", nullptr}, + {0xf0919525, "AndroidCryptoNative_CipherReset", nullptr}, + {0xf0e499c4, "SystemNative_PRead", nullptr}, + {0xf1bb5b47, "SystemNative_ReadLink", nullptr}, + {0xf23e6314, "AndroidCryptoNative_RsaCreate", nullptr}, + {0xf2a49cf0, "SystemNative_CloseSocketEventPort", nullptr}, + {0xf39b1c3a, "SystemNative_GetCryptographicallySecureRandomBytes", nullptr}, + {0xf3b9c879, "AndroidCryptoNative_X509Encode", nullptr}, + {0xf432ab33, "SystemNative_CloseDir", nullptr}, + {0xf4a5a1c8, "SystemNative_SysLog", nullptr}, + {0xf500c9d3, "SystemNative_GetActiveUdpListeners", nullptr}, + {0xf57828fb, "SystemNative_IsATty", nullptr}, + {0xf5918f53, "SystemNative_GetSocketAddressSizes", nullptr}, + {0xf6141499, "AndroidCryptoNative_X509ChainBuild", nullptr}, + {0xf629d20f, "SystemNative_Shutdown", nullptr}, + {0xf6b01c6b, "SystemNative_FreeEnviron", nullptr}, + {0xf6bfedad, "SystemNative_ReadEvents", nullptr}, + {0xf91cf365, "AndroidCryptoNative_Aes128Ccm", nullptr}, + {0xf94a4828, "SystemNative_GetEUid", nullptr}, + {0xf993f426, "SystemNative_Free", nullptr}, + {0xfa97914b, "SystemNative_MMap", nullptr}, + {0xfad61722, "AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey", nullptr}, + {0xfae25aa7, "GlobalizationNative_LastIndexOf", nullptr}, + {0xfb89157f, "SystemNative_GetGroups", nullptr}, + {0xfc83423c, "SystemNative_GetRawSockOpt", nullptr}, + {0xfd9099cc, "SystemNative_GetUInt64OSThreadId", nullptr}, + {0xfe2f2c47, "SystemNative_DrainAutoreleasePool", nullptr}, + {0xfeb6c5c7, "SystemNative_WaitPidExitedNoHang", nullptr}, + {0xff3b4cfa, "SystemNative_GetFileSystemType", nullptr}, + {0xff975200, "SystemNative_Realloc", nullptr}, + }}; + + +constexpr hash_t java_interop_library_hash = 0x6e36e350; +constexpr hash_t xa_internal_api_library_hash = 0x13c9bd62; +constexpr hash_t system_native_library_hash = 0x5b9ade60; +constexpr hash_t system_io_compression_native_library_hash = 0xafe3142c; +constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93625cd; +constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a; +#endif + +constexpr size_t internal_pinvokes_count = 2; +constexpr size_t dotnet_pinvokes_count = 477; +} // end of anonymous namespace diff --git a/src/native/clr/include/host/os-bridge.hh b/src/native/clr/include/host/os-bridge.hh index 8634970d975..50ee3c20166 100644 --- a/src/native/clr/include/host/os-bridge.hh +++ b/src/native/clr/include/host/os-bridge.hh @@ -1,7 +1,11 @@ #pragma once +#include + #include +#include "../runtime-base/logger.hh" + namespace xamarin::android { class OSBridge { @@ -9,8 +13,29 @@ namespace xamarin::android { static void initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept; static auto lref_to_gref (JNIEnv *env, jobject lref) noexcept -> jobject; + static auto get_gc_gref_count () noexcept -> int + { + return gc_gref_count; + } + + static auto get_gc_weak_gref_count () noexcept -> int + { + return gc_weak_gref_count; + } + + static auto _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept -> int; + + private: + static auto _monodroid_gref_inc () noexcept -> int; + static auto _monodroid_gref_dec () noexcept -> int; + static auto _get_stack_trace_line_end (char *m) noexcept -> char*; + static void _write_stack_trace (FILE *to, char *from, LogCategories = LOG_NONE) noexcept; + private: static inline jclass GCUserPeer_class = nullptr; static inline jmethodID GCUserPeer_ctor = nullptr; + + static inline int gc_gref_count = 0; + static inline int gc_weak_gref_count = 0; }; } diff --git a/src/native/clr/include/host/pinvoke-override.hh b/src/native/clr/include/host/pinvoke-override.hh new file mode 100644 index 00000000000..73c94086194 --- /dev/null +++ b/src/native/clr/include/host/pinvoke-override.hh @@ -0,0 +1,223 @@ +#pragma once + +#include +#include + +// NDEBUG causes robin_map.h not to include which, in turn, prevents indirect inclusion of . +// conflicts with our std::mutex definition in cppcompat.hh +#if !defined (NDEBUG) +#define NDEBUG +#define NDEBUG_UNDEFINE +#endif + +// hush some compiler warnings +#if defined (__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif // __clang__ + +#include + +#if defined (__clang__) +#pragma clang diagnostic pop +#endif // __clang__ + +#if defined (NDEBUG_UNDEFINE) +#undef NDEBUG +#undef NDEBUG_UNDEFINE +#endif + +#include "../runtime-base/monodroid-dl.hh" +#include "../shared/xxhash.hh" + +namespace xamarin::android { + struct PinvokeEntry + { + hash_t hash; + const char *name; + void *func; + }; + + struct string_hash + { + [[gnu::always_inline]] + xamarin::android::hash_t operator() (std::string const& s) const noexcept + { + return xamarin::android::xxhash::hash (s.c_str (), s.length ()); + } + }; + + class PinvokeOverride + { + using pinvoke_api_map = tsl::robin_map< + std::string, + void*, + string_hash, + std::equal_to, + std::allocator>, + true + >; + + using pinvoke_api_map_ptr = pinvoke_api_map*; + using pinvoke_library_map = tsl::robin_map< + std::string, + pinvoke_api_map_ptr, + string_hash, + std::equal_to, + std::allocator>, + true + >; + + static inline constexpr pinvoke_library_map::size_type LIBRARY_MAP_INITIAL_BUCKET_COUNT = 1uz; + + public: + [[gnu::always_inline]] + static auto load_library_symbol (const char *library_name, const char *symbol_name, void **dso_handle = nullptr) noexcept -> void* + { + void *lib_handle = dso_handle == nullptr ? nullptr : *dso_handle; + + if (lib_handle == nullptr) { + // We're being called as part of the p/invoke mechanism, we don't need to look in the AOT cache + constexpr bool PREFER_AOT_CACHE = false; + lib_handle = MonodroidDl::monodroid_dlopen (library_name, microsoft::java_interop::JAVA_INTEROP_LIB_LOAD_LOCALLY, PREFER_AOT_CACHE); + if (lib_handle == nullptr) { + log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", optional_string (library_name), optional_string (symbol_name)); + return nullptr; + } + + if (dso_handle != nullptr) { + void *expected_null = nullptr; + if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { + log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", optional_string (library_name)); + } + } + } + + void *entry_handle = MonodroidDl::monodroid_dlsym (lib_handle, symbol_name); + if (entry_handle == nullptr) { + log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", optional_string (library_name), optional_string (symbol_name)); + return nullptr; + } + + return entry_handle; + } + + static auto load_library_entry (std::string const& library_name, std::string const& entrypoint_name, pinvoke_api_map_ptr api_map) noexcept -> void* + { + // Make sure some other thread hasn't just added the entry + auto iter = api_map->find (entrypoint_name); + if (iter != api_map->end () && iter->second != nullptr) { + return iter->second; + } + + void *entry_handle = load_library_symbol (library_name.c_str (), entrypoint_name.c_str ()); + if (entry_handle == nullptr) { + // error already logged + return nullptr; + } + + log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); + (*api_map)[entrypoint_name] = entry_handle; + return entry_handle; + } + + static void load_library_entry (const char *library_name, const char *entrypoint_name, PinvokeEntry &entry, void **dso_handle) noexcept + { + void *entry_handle = load_library_symbol (library_name, entrypoint_name, dso_handle); + void *expected_null = nullptr; + + bool already_loaded = !__atomic_compare_exchange ( + /* ptr */ &entry.func, + /* expected */ &expected_null, + /* desired */ &entry_handle, + /* weak */ false, + /* success_memorder */ __ATOMIC_ACQUIRE, + /* failure_memorder */ __ATOMIC_RELAXED + ); + + if (already_loaded) { + log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); + } + } + + static auto fetch_or_create_pinvoke_map_entry (std::string const& library_name, std::string const& entrypoint_name, hash_t entrypoint_name_hash, pinvoke_api_map_ptr api_map, bool need_lock) noexcept -> void* + { + auto iter = api_map->find (entrypoint_name, entrypoint_name_hash); + if (iter != api_map->end () && iter->second != nullptr) { + return iter->second; + } + + if (!need_lock) { + return load_library_entry (library_name, entrypoint_name, api_map); + } + + StartupAwareLock lock (pinvoke_map_write_lock); + return load_library_entry (library_name, entrypoint_name, api_map); + } + + [[gnu::always_inline]] + static auto find_pinvoke_address (hash_t hash, const PinvokeEntry *entries, size_t entry_count) noexcept -> PinvokeEntry* + { + while (entry_count > 0uz) { + const size_t mid = entry_count / 2uz; + const PinvokeEntry *const ret = entries + mid; + const std::strong_ordering result = hash <=> ret->hash; + + if (result < 0) { + entry_count = mid; + } else if (result > 0) { + entries = ret + 1; + entry_count -= mid + 1uz; + } else { + return const_cast(ret); + } + } + + return nullptr; + } + + [[gnu::always_inline, gnu::flatten]] + static auto handle_other_pinvoke_request (const char *library_name, hash_t library_name_hash, const char *entrypoint_name, hash_t entrypoint_name_hash) noexcept -> void* + { + std::string lib_name {library_name}; + std::string entry_name {entrypoint_name}; + + auto iter = other_pinvoke_map.find (lib_name, library_name_hash); + void *handle = nullptr; + if (iter == other_pinvoke_map.end ()) { + StartupAwareLock lock (pinvoke_map_write_lock); + + pinvoke_api_map_ptr lib_map; + // Make sure some other thread hasn't just added the map + iter = other_pinvoke_map.find (lib_name, library_name_hash); + if (iter == other_pinvoke_map.end () || iter->second == nullptr) { + lib_map = new pinvoke_api_map (1); + other_pinvoke_map[lib_name] = lib_map; + } else { + lib_map = iter->second; + } + + handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); + } else { + if (iter->second == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", optional_string (library_name)); + return nullptr; // fall back to `monodroid_dlopen` + } + + handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, iter->second, /* need_lock */ true); + } + + return handle; + } + + static auto monodroid_pinvoke_override (const char *library_name, const char *entrypoint_name) noexcept -> void*; + + private: + static inline std::mutex pinvoke_map_write_lock{}; + static inline pinvoke_library_map other_pinvoke_map{}; + static inline void *system_native_library_handle = nullptr; + static inline void *system_security_cryptography_native_android_library_handle = nullptr; + static inline void *system_io_compression_native_library_handle = nullptr; + static inline void *system_globalization_native_library_handle = nullptr; + }; +} diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index 70675d10315..ae92a1977da 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -23,6 +23,9 @@ namespace xamarin::android { inline static std::array single_app_lib_directory{}; inline static std::span app_lib_directories; + // TODO: override dirs not implemented + inline static std::array override_dirs{}; + static constexpr std::array android_abi_names { std::string_view { "unknown" }, // CPU_KIND_UNKNOWN std::string_view { "armeabi-v7a" }, // CPU_KIND_ARM @@ -96,8 +99,16 @@ namespace xamarin::android { static void detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcept; static void setup_environment () noexcept; static void setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) noexcept; + static auto load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check) noexcept -> void*; + static auto load_dso_from_any_directories (const char *name, unsigned int dl_flags) noexcept -> void*; private: + static auto get_full_dso_path (std::string const& base_dir, const char *dso_path, dynamic_local_string& path) noexcept -> bool; + + template // TODO: replace with a concept + static auto load_dso_from_specified_dirs (TContainer directories, const char *dso_name, unsigned int dl_flags) noexcept -> void*; + static auto load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags) noexcept -> void*; + static auto load_dso_from_override_dirs (const char *name, unsigned int dl_flags) noexcept -> void*; static auto lookup_system_property (std::string_view const &name, size_t &value_len) noexcept -> const char*; static auto monodroid__system_property_get (std::string_view const&, char *sp_value, size_t sp_value_len) noexcept -> int; static auto get_max_gref_count_from_system () noexcept -> long; diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh new file mode 100644 index 00000000000..72a0d9dcc32 --- /dev/null +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -0,0 +1,6 @@ +#pragma once + +#include + +int _monodroid_gref_get (); +int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable); diff --git a/src/native/clr/include/runtime-base/strings.hh b/src/native/clr/include/runtime-base/strings.hh index aae49968f84..dc2933f4259 100644 --- a/src/native/clr/include/runtime-base/strings.hh +++ b/src/native/clr/include/runtime-base/strings.hh @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -612,6 +613,12 @@ namespace xamarin::android { return assign (sv.data (), sv.size ()); } + [[gnu::always_inline]] + auto assign (std::string const& s) noexcept -> string_base& + { + return assign (s.data (), s.size ()); + } + template [[gnu::always_inline]] auto assign (const char (&s)[Size]) noexcept -> string_base& { diff --git a/src/native/clr/include/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 2d87bbffa66..02b559fcf78 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -176,6 +176,15 @@ namespace xamarin::android { }; } + static auto is_path_rooted (const char *path) noexcept -> bool + { + if (path == nullptr) { + return false; + } + + return path [0] == '/'; + } + private: // TODO: needs some work to accept mixed params of different accepted types template TBuffer, detail::PathComponentString ...TPart> diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index b97651b733d..cd3a15d4495 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -1,6 +1,9 @@ #include #include +#include +#include + #include #include #include @@ -8,7 +11,9 @@ #include #include +using namespace microsoft::java_interop; using namespace xamarin::android; + using std::operator""sv; #if defined(DEBUG) @@ -403,3 +408,86 @@ AndroidSystem::get_max_gref_count_from_system () noexcept -> long return max; } + +auto AndroidSystem::get_full_dso_path (std::string const& base_dir, const char *dso_path, dynamic_local_string& path) noexcept -> bool +{ + if (dso_path == nullptr) { + return false; + } + + if (base_dir.empty () || 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 (base_dir) + .append ("/"sv) + .append_c (dso_path); + + return true; +} + +auto AndroidSystem::load_dso (const char *path, unsigned int dl_flags, bool skip_exists_check) noexcept -> void* +{ + if (path == nullptr || *path == '\0') { + return nullptr; + } + + log_info (LOG_ASSEMBLY, "Trying to load shared library '{}'", path); + if (!skip_exists_check && !is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { + log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); + return nullptr; + } + + char *error = nullptr; + void *handle = java_interop_lib_load (path, dl_flags, &error); + if (handle == nullptr && Util::should_log (LOG_ASSEMBLY)) { + log_info_nocheck (LOG_ASSEMBLY, "Failed to load shared library '{}'. {}", path, error); + } + java_interop_free (error); + return handle; +} + +template [[gnu::always_inline]] // TODO: replace with a concept +auto AndroidSystem::load_dso_from_specified_dirs (TContainer directories, const char *dso_name, unsigned int dl_flags) noexcept -> void* +{ + if (dso_name == nullptr) { + return nullptr; + } + + dynamic_local_string full_path; + for (std::string const& dir : directories) { + if (!get_full_dso_path (dir, dso_name, full_path)) { + continue; + } + + void *handle = load_dso (full_path.get (), dl_flags, false); + if (handle != nullptr) { + return handle; + } + } + + return nullptr; +} + +auto AndroidSystem::load_dso_from_app_lib_dirs (const char *name, unsigned int dl_flags) noexcept -> void* +{ + return load_dso_from_specified_dirs (app_lib_directories, name, dl_flags); +} + +auto AndroidSystem::load_dso_from_override_dirs (const char *name, unsigned int dl_flags) noexcept -> void* +{ + if constexpr (Constants::is_release_build) { + return nullptr; + } else { + return load_dso_from_specified_dirs (AndroidSystem::override_dirs, name, dl_flags); + } +} + +[[gnu::flatten]] +auto AndroidSystem::load_dso_from_any_directories (const char *name, unsigned int dl_flags) noexcept -> void* +{ + void *handle = load_dso_from_override_dirs (name, dl_flags); + if (handle == nullptr) { + handle = load_dso_from_app_lib_dirs (name, dl_flags); + } + return handle; +} From e0fce177bf4693386412177f10eca8c1d4ca79a2 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 5 Feb 2025 10:08:07 +0100 Subject: [PATCH 093/143] Oops, kind of need this one --- src/native/clr/include/runtime-base/monodroid-dl.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/clr/include/runtime-base/monodroid-dl.hh b/src/native/clr/include/runtime-base/monodroid-dl.hh index c35a89052a4..d52e4d6f13a 100644 --- a/src/native/clr/include/runtime-base/monodroid-dl.hh +++ b/src/native/clr/include/runtime-base/monodroid-dl.hh @@ -7,11 +7,11 @@ #include -#include +#include "../shared/xxhash.hh" #include "../xamarin-app.hh" #include "android-system.hh" -#include +#include "search.hh" #include "startup-aware-lock.hh" namespace xamarin::android From 3c34b2bb7e5b3c9d3e7ebcff70df1d23e382b376 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 5 Feb 2025 17:37:56 +0100 Subject: [PATCH 094/143] Notes + logging --- CLR-Host-Notes.md | 25 +++++++++++++++++++++++++ src/native/clr/host/pinvoke-override.cc | 5 ++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CLR-Host-Notes.md b/CLR-Host-Notes.md index d89f989716e..5c623e14f15 100644 --- a/CLR-Host-Notes.md +++ b/CLR-Host-Notes.md @@ -12,3 +12,28 @@ names should be UTF-8, but we can generate lookup tables for those at application build time (e.g. indexed by an xxHash of the Unicode version of the name) - no conversion at run time. * We need declarations of all he possible HRESULT errors (`S_OK` etc) + +## Stuff that should be changed + +### Logging +Currently, most of the messages logged by the runtime end up in `/dev/null` (either because they +are disabled in release build or because they log to stdio which doesn't work on Android). + +Logcat is the only way to get information from remote devices, especially via Google Play Console. + +We should log to logcat: + + + C++ exception messages + + abort() messages / fatal errors + + warnings + + errors + +A subsystem should be added which will provide a single function that will do actual output, implementation of which +will be specific to the platform. API should allow specification of severity, the actual message, and possibly a flag +to indicate whether the process should be aborted (the decision might also be based on the severity). Severity should +be shared between all targets, which then can (if needed) translate it to the target platform's value(s), if any. + +### Process termination +Runtime currently calls `abort()` in several places. This should probably become part of the host contract instead. +Being part of the contract, the target platform could implement process termination on `abort()` in a uniform way +(includes platform-specific logging, preparation etc) diff --git a/src/native/clr/host/pinvoke-override.cc b/src/native/clr/host/pinvoke-override.cc index 11fd5708a20..a2edc9ef9b2 100644 --- a/src/native/clr/host/pinvoke-override.cc +++ b/src/native/clr/host/pinvoke-override.cc @@ -88,5 +88,8 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept { - return PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); + log_info (LOG_ASSEMBLY, "clr_pinvoke_override (\"{}\", \"{}\")", library_name, entry_point_name); + void *ret = PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); + log_debug (LOG_DEFAULT, "p/invoke {}found", ret == nullptr ? "not"sv : ""sv); + return ret; } From 15778ad23169dc4525b483faf67125f356b041aa Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 6 Feb 2025 11:15:28 +0100 Subject: [PATCH 095/143] Remove a number of hacks, now that runtime packs are available --- ...oft.Android.Sdk.AssemblyResolution.targets | 7 +- ...HackInjectAndroidRuntimeSharedLibraries.cs | 71 ---------- .../Tasks/MaybeUseLocalClr.cs | 20 +-- .../Tasks/RecreateResolvedRuntimePacks.cs | 123 +++++------------- 4 files changed, 37 insertions(+), 184 deletions(-) delete mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs 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 e590d56e31e..2e562244adf 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 @@ -52,6 +52,7 @@ _ResolveAssemblies MSBuild target. @@ -129,12 +130,6 @@ _ResolveAssemblies MSBuild target. - - - - diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs deleted file mode 100644 index e6040ee8444..00000000000 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CoreClrHackInjectAndroidRuntimeSharedLibraries.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using Microsoft.Android.Build.Tasks; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Xamarin.Android.Tools; - -namespace Xamarin.Android.Tasks; - -// -// HACK! HACK! To be removed when CoreCLR runtime packs work properly. -// -// Injects CoreCLR runtime pack shared libraries into the `ResolvedFileToPublish` -// item group. -// -public class CoreClrHackInjectAndroidRuntimeSharedLibraries : AndroidTask -{ - public override string TaskPrefix => "CCHIARSL"; - - [Required] - public ITaskItem[] ResolvedFilesToPublish { get; set; } - - [Required] - public string AndroidRuntime { get; set; } = String.Empty; - - [Output] - public ITaskItem[] SharedLibrariesToAdd { get; set; } = Array.Empty (); - - public override bool RunTask () - { - if (String.Compare (AndroidRuntime, "CoreCLR", StringComparison.OrdinalIgnoreCase) != 0) { - return true; - } - - var sharedLibsToAdd = new List (); - foreach (ITaskItem item in ResolvedFilesToPublish) { - string fileName = Path.GetFileName (item.ItemSpec); - string dirName = Path.GetDirectoryName (item.ItemSpec).Replace ("Mono", "CoreCLR"); - ITaskItem newItem; - if (String.Compare (fileName, "libmono-android.release.so", StringComparison.OrdinalIgnoreCase) == 0) { - newItem = MakeItem (Path.Combine (dirName, "libnet-android.release.so"), item); - } else if (String.Compare (fileName, "libmono-android.debug.so", StringComparison.OrdinalIgnoreCase) == 0) { - newItem = MakeItem (Path.Combine (dirName, "libnet-android.debug.so"), item); - } else { - continue; - } - - sharedLibsToAdd.Add (newItem); - } - - SharedLibrariesToAdd = sharedLibsToAdd.ToArray (); - return !Log.HasLoggedErrors; - } - - ITaskItem MakeItem (string identity, ITaskItem templateItem) - { - var item = new TaskItem (identity); - templateItem.CopyMetadataTo (item); - - string fileName = Path.GetFileName (identity); - item.SetMetadata ("DestinationSubPath", fileName); - item.SetMetadata ("RelativePath", fileName); - - // No need to null check the metadata value - if it isn't there, then something's broken and we - // will let it crash. - item.SetMetadata ("NuGetPackageId", item.GetMetadata ("NuGetPackageId").Replace ("Mono", "CoreCLR")); - return item; - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs index b84e7aac64c..f9e1a4c4ece 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs @@ -118,7 +118,7 @@ void MakeLocalPackItem (ITaskItem required, List itemsToAdd, HashSet< void ProcessItem (ITaskItem item, List itemsToRemove, List requiredClrItems, HashSet supportedArchitectures) { - if (LinuxBionicHack (item, itemsToRemove) || CoreClrItem (item, itemsToRemove, requiredClrItems)) { + if (CoreClrItem (item, itemsToRemove, requiredClrItems)) { return; } @@ -146,22 +146,4 @@ bool CoreClrItem (ITaskItem item, List itemsToRemove, List requiredClrItems.Add (item); return true; } - - bool LinuxBionicHack (ITaskItem item, List itemsToRemove) - { - string? nugetId = item.GetMetadata ("NuGetPackageId"); - if (String.IsNullOrEmpty (nugetId)) { - return false; - } - - const string BionicNugetIdPrefix = "Microsoft.NETCore.App.Runtime.linux-bionic-"; - if (!nugetId.StartsWith (BionicNugetIdPrefix, StringComparison.OrdinalIgnoreCase)) { - return false; - } - - Log.LogWarning ($"[MaybeUseLocalClr] HACK! HACK! Ignoring linux-bionic item {item}. Remove once SDK is updated!"); - itemsToRemove.Add (item); - - return true; - } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs index a48f9617906..3c660535005 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs @@ -69,75 +69,7 @@ public override bool RunTask () var maybeIgnoreLibs = new List (); var runtimePackPaths = new List (); - // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK - HashSet? coreClrHackLibcItems = AndroidRuntime == "CoreCLR" ? new HashSet () : null; - if (coreClrHackLibcItems != null) { - LogHackWarning (); - } - // HACK END - foreach (ITaskItem library in ResolvedNativeLibraries) { - // HACK START: when CoreCLR runtime pack is properly resolved by the SDK, this method's body - // should be moved here and the method removed. - MaybeMakeRuntimePackItem (library, useCoreClrHack: true); - // HACK END - } - - // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK - if (coreClrHackLibcItems != null) { - LogHackWarning (); - foreach (ITaskItem item in coreClrHackLibcItems) { - string fakePath = item.ItemSpec.Replace ("Mono", "CoreCLR"); - if (fakePath.IndexOf ("CoreCLR") < 0) { - throw new InvalidOperationException ("CoreCLR runtime pack hack doesn't work"); - } - - var fakeLibcItem = new TaskItem (fakePath); - item.CopyMetadataTo (fakeLibcItem); - fakeLibcItem.SetMetadata ("NuGetPackageId", item.GetMetadata ("NuGetPackageId").Replace ("Mono", "CoreCLR")); - MaybeMakeRuntimePackItem (fakeLibcItem, useCoreClrHack: false); - } - } - // HACK END - ResolvedRuntimePacks = runtimePacks.Values.ToArray (); - - var librariesToIgnore = new List (); - foreach (string path in runtimePackPaths) { - string runtimePackPath = path; - if (path[path.Length - 1] != Path.DirectorySeparatorChar) { - runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; - } - - // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK - if (coreClrHackLibcItems != null) { - LogHackWarning (); - runtimePackPath = runtimePackPath.Replace ("CoreCLR", "Mono"); - } - // HACK END - foreach (ITaskItem library in maybeIgnoreLibs) { - if (library.ItemSpec.StartsWith (runtimePackPath)) { - librariesToIgnore.Add (library); - } - } - }; - SharedLibrariesToIgnore = librariesToIgnore.ToArray (); - - return !Log.HasLoggedErrors; - - bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue) - { - metadataValue = item.GetMetadata (metadataName); - return !String.IsNullOrEmpty (metadataValue); - } - - bool PackNativeFileExists (string packageDir, string rid, string fileName) - { - string packFilePath = Path.Combine (packageDir, "runtimes", rid, "native", fileName); - return File.Exists (packFilePath); - } - - void MaybeMakeRuntimePackItem (ITaskItem library, bool useCoreClrHack) - { foreach (string libPathTail in ignoreLibNames) { if (!library.ItemSpec.EndsWith (libPathTail, StringComparison.OrdinalIgnoreCase)) { continue; @@ -148,43 +80,32 @@ void MaybeMakeRuntimePackItem (ITaskItem library, bool useCoreClrHack) } if (!library.ItemSpec.EndsWith (libcPath, StringComparison.OrdinalIgnoreCase)) { - return; + continue; } if (!GetMetadata (library, "RuntimeIdentifier", out string? rid) || runtimePacks.ContainsKey (rid)) { - return; + continue; } if (!GetMetadata (library, "NuGetPackageId", out string? nugetPackageId)) { - return; + continue; } if (!GetMetadata (library, "NuGetPackageVersion", out string? nugetPackageVersion)) { - return; + continue; } string tail = String.Format ("{0}runtimes{0}{1}{2}", Path.DirectorySeparatorChar, rid, libcPath); int tailIndex = library.ItemSpec.IndexOf (tail); if (tailIndex < 0) { - return; + continue; } string packageDir = library.ItemSpec.Substring (0, tailIndex); - // HACK START: must be removed when CoreCLR runtime pack is properly resolved by the SDK - if (useCoreClrHack && coreClrHackLibcItems != null) { - LogHackWarning (); - coreClrHackLibcItems.Add (library); - } - // HACK END - - // Double-check that this is in fact our runtime pack. This is needed to avoid the (however improbable) - // situation where the application references a nuget which comes with `libc.so` and we mistakenly identify - // it to be our runtime pack. - // Archive DSO stub must always exist if (!PackNativeFileExists (packageDir, rid, DSOWrapperGenerator.StubFileName)) { Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain '{DSOWrapperGenerator.StubFileName}'. Pack ignored."); - return; + continue; } // Either one of the runtime libraries must exist @@ -198,7 +119,7 @@ void MaybeMakeRuntimePackItem (ITaskItem library, bool useCoreClrHack) } if (!runtimeLibraryFound) { Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain any {AndroidRuntime} runtime shared libraries. Pack ignored."); - return; + continue; } var pack = new TaskItem (nugetPackageId); @@ -212,9 +133,35 @@ void MaybeMakeRuntimePackItem (ITaskItem library, bool useCoreClrHack) runtimePacks.Add (rid, pack); } - void LogHackWarning () + ResolvedRuntimePacks = runtimePacks.Values.ToArray (); + + var librariesToIgnore = new List (); + foreach (string path in runtimePackPaths) { + string runtimePackPath = path; + if (path[path.Length - 1] != Path.DirectorySeparatorChar) { + runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; + } + + foreach (ITaskItem library in maybeIgnoreLibs) { + if (library.ItemSpec.StartsWith (runtimePackPath)) { + librariesToIgnore.Add (library); + } + } + }; + SharedLibrariesToIgnore = librariesToIgnore.ToArray (); + + return !Log.HasLoggedErrors; + + bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue) + { + metadataValue = item.GetMetadata (metadataName); + return !String.IsNullOrEmpty (metadataValue); + } + + bool PackNativeFileExists (string packageDir, string rid, string fileName) { - Log.LogWarning ("[RecreateResolvedRuntimePacks] HACK! HACK! Using CoreCLR resolution hack. Remove once SDK is updated!"); + string packFilePath = Path.Combine (packageDir, "runtimes", rid, "native", fileName); + return File.Exists (packFilePath); } } } From e9bd6c5e5c4cb723d31ed1da88cf17e956cf0942 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 6 Feb 2025 11:27:43 +0100 Subject: [PATCH 096/143] One more hack gone --- .../Microsoft.Android.Sdk.AssemblyResolution.targets | 7 ++++--- .../targets/Microsoft.Android.Sdk.targets | 9 --------- 2 files changed, 4 insertions(+), 12 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 2e562244adf..9dbd4ca4912 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 @@ -70,6 +70,10 @@ _ResolveAssemblies MSBuild target. anything in a `dotnet new android` template, and without them the process crashes. For now defining them to be root assemblies makes things work, but it's not the correct solution since the assemblies mentioned here won't be trimmed themselves. + This can be removed when the local CLR hack is gone (replaced by a locally built runtime + pack nuget), as then the assemblies will be properly trimmed and references to the + assemblies below will be removed (they contain type forwards which are resolved to the + target assembly by the trimmer) --> @@ -119,9 +123,6 @@ _ResolveAssemblies MSBuild target. <_ProjectToBuild Include="$(MSBuildProjectFile)" AdditionalProperties="RuntimeIdentifier=%(_RIDs.Identity);$(_AdditionalProperties)" /> - - - - - - - %(RuntimePackRuntimeIdentifiers);android-arm64 - From d1f69997feeb88242922e71fdb0c3cc967006b31 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 10 Feb 2025 10:23:16 +0100 Subject: [PATCH 097/143] Sync CoreCLR host with the latest native changes in main --- src/native/clr/host/host.cc | 1 - src/native/clr/include/host/host.hh | 1 - 2 files changed, 2 deletions(-) diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 2fab41760b6..0743bc669ea 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -194,7 +194,6 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); init.grefClass = HostUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); - init.Class_forName = env->GetStaticMethodID (init.grefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); jclass lrefLoaderClass = env->GetObjectClass (loader); init.Loader_loadClass = env->GetMethodID (lrefLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index c06b9a0f374..4cffc3dfbe3 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -18,7 +18,6 @@ namespace xamarin::android { jobject grefLoader; jmethodID Loader_loadClass; jclass grefClass; - jmethodID Class_forName; unsigned int logCategories; int version; int grefGcThreshold; From 6b55c394328c5c9c1c6bc3937a7123847510da0f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 10 Feb 2025 11:28:53 +0100 Subject: [PATCH 098/143] Create an LlvmIrStringVariable instance when adding a string variable --- .../Utilities/LlvmIrGenerator/LlvmIrModule.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs index fe2914262f2..3baa55fd5aa 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs @@ -270,18 +270,17 @@ public LlvmIrGlobalVariable AddGlobalVariable (Type type, string name, object? v LlvmIrGlobalVariable ret; if (type == typeof(string)) { // The cast to `string?` is intentionally meant to throw if `value` type isn't a string. - ret = new LlvmIrStringVariable (name, new StringHolder ((string?)value), options) { + ret = new LlvmIrStringVariable (name, new StringHolder ((string?)value)) { Comment = comment, }; - AddStringGlobalVariable ((LlvmIrStringVariable)ret); } else { ret = new LlvmIrGlobalVariable (type, name, options) { Value = value, Comment = comment, }; - Add (ret); } + Add (ret); return ret; } From 4fdd003d51ca9b6f0ffdd1b3f05a253529a215b2 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 10 Feb 2025 20:02:06 +0100 Subject: [PATCH 099/143] Let's try this --- .../Utilities/LlvmIrGenerator/LlvmIrModule.cs | 23 ++++++++++++++----- .../LlvmIrGenerator/LlvmIrStringManager.cs | 12 +++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs index 3baa55fd5aa..6cd03079f4c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs @@ -273,14 +273,15 @@ public LlvmIrGlobalVariable AddGlobalVariable (Type type, string name, object? v ret = new LlvmIrStringVariable (name, new StringHolder ((string?)value)) { Comment = comment, }; + AddStringGlobalVariable ((LlvmIrStringVariable)ret); } else { ret = new LlvmIrGlobalVariable (type, name, options) { Value = value, Comment = comment, }; + Add (ret); } - Add (ret); return ret; } @@ -401,19 +402,29 @@ void AddStandardGlobalVariable (LlvmIrGlobalVariable variable) globalVariables.Add (variable); } + void EnsureStringManager () + { + if (stringManager == null) { + stringManager = new LlvmIrStringManager (log); + } + } + void AddStringGlobalVariable (LlvmIrStringVariable variable, string? stringGroupName = null, string? stringGroupComment = null, string? symbolSuffix = null) { - RegisterString ((string)variable.Value, stringGroupName, stringGroupComment, symbolSuffix, variable.Encoding); + RegisterString (variable, stringGroupName, stringGroupComment, symbolSuffix); AddStandardGlobalVariable (variable); } + public void RegisterString (LlvmIrStringVariable variable, string? stringGroupName = null, string? stringGroupComment = null, string? symbolSuffix = null) + { + EnsureStringManager (); + stringManager.Add (variable, stringGroupName, stringGroupComment, symbolSuffix); + } + public void RegisterString (string value, string? stringGroupName = null, string? stringGroupComment = null, string? symbolSuffix = null, LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8, StringComparison comparison = StringComparison.Ordinal) { - if (stringManager == null) { - stringManager = new LlvmIrStringManager (log); - } - + EnsureStringManager (); stringManager.Add (value, stringGroupName, stringGroupComment, symbolSuffix, encoding, comparison); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs index 917ce8e4b1d..6a6f634962c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs @@ -26,6 +26,12 @@ public LlvmIrStringManager (TaskLoggingHelper log) stringGroups.Add (defaultGroup); } + public LlvmIrStringVariable Add (LlvmIrStringVariable variable, string? groupName = null, string? groupComment = null, string? symbolSuffix = null) + { + // Let it throw if Value isn't a StringHolder, it must be. + return Add((StringHolder)variable.Value, groupName, groupComment, symbolSuffix); + } + public LlvmIrStringVariable Add (string value, string? groupName = null, string? groupComment = null, string? symbolSuffix = null, LlvmIrStringEncoding encoding = LlvmIrStringEncoding.UTF8, StringComparison comparison = StringComparison.Ordinal) { @@ -33,7 +39,11 @@ public LlvmIrStringVariable Add (string value, string? groupName = null, string? throw new ArgumentNullException (nameof (value)); } - var holder = new StringHolder (value, encoding, comparison); + return Add (new StringHolder (value, encoding, comparison), groupName, groupComment, symbolSuffix); + } + + LlvmIrStringVariable Add (StringHolder holder, string? groupName = null, string? groupComment = null, string? symbolSuffix = null) + { if (stringSymbolCache.TryGetValue (holder, out LlvmIrStringVariable? stringVar) && stringVar != null) { return stringVar; } From 64495aef976d6039fe48463405bd604aaa51a2fa Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 11 Feb 2025 14:08:57 +0100 Subject: [PATCH 100/143] "Namespace" LLVM IR strings" --- .../Utilities/LlvmIrGenerator/LlvmIrModule.cs | 4 +++- .../Utilities/LlvmIrGenerator/LlvmIrStringManager.cs | 8 +++++++- .../Utilities/LlvmIrGenerator/LlvmIrVariable.cs | 8 ++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs index 6cd03079f4c..ab38d7b2ecd 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs @@ -49,6 +49,8 @@ partial class LlvmIrModule public readonly LlvmIrTypeCache TypeCache; + public string? DefaultStringGroup { get; set; } + public LlvmIrModule (LlvmIrTypeCache cache, TaskLoggingHelper log) { this.log = log; @@ -405,7 +407,7 @@ void AddStandardGlobalVariable (LlvmIrGlobalVariable variable) void EnsureStringManager () { if (stringManager == null) { - stringManager = new LlvmIrStringManager (log); + stringManager = new LlvmIrStringManager (log, DefaultStringGroup); } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs index 6a6f634962c..7290a87a5f5 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringManager.cs @@ -9,6 +9,8 @@ partial class LlvmIrModule { protected class LlvmIrStringManager { + readonly string defaultGroupName = "str"; + Dictionary stringSymbolCache = new Dictionary (); Dictionary stringGroupCache = new Dictionary (StringComparer.Ordinal); List stringGroups = new List (); @@ -18,9 +20,13 @@ protected class LlvmIrStringManager public List StringGroups => stringGroups; - public LlvmIrStringManager (TaskLoggingHelper log) + public LlvmIrStringManager (TaskLoggingHelper log, string? defaultStringGroup = null) { this.log = log; + if (!String.IsNullOrEmpty (defaultStringGroup)) { + defaultGroupName = defaultStringGroup; + } + defaultGroup = new LlvmIrStringGroup (); stringGroupCache.Add (String.Empty, defaultGroup); stringGroups.Add (defaultGroup); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs index d6571f3760e..18c67db93a6 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs @@ -301,8 +301,8 @@ class LlvmIrStringVariable : LlvmIrGlobalVariable public string IrType { get; } public bool IsConstantStringLiteral { get; } - public LlvmIrStringVariable (string name, StringHolder value) - : base (typeof(string), name, LlvmIrVariableOptions.LocalString) + public LlvmIrStringVariable (string name, StringHolder value, LlvmIrVariableOptions? options = null) + : base (typeof(string), name, options ?? LlvmIrVariableOptions.GlobalConstexprString) { Value = value; Encoding = value.Encoding; @@ -322,8 +322,8 @@ public LlvmIrStringVariable (string name, StringHolder value) } } - public LlvmIrStringVariable (string name, string value, LlvmIrStringEncoding encoding, StringComparison comparison = StringComparison.Ordinal) - : this (name, new StringHolder (value, encoding, comparison)) + public LlvmIrStringVariable (string name, string value, LlvmIrStringEncoding encoding, StringComparison comparison = StringComparison.Ordinal, LlvmIrVariableOptions? options = null) + : this (name, new StringHolder (value, encoding, comparison), options) {} } From a6af727af39ba96883dbc0d2d7a978be7c5c0b6b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 11 Feb 2025 19:17:41 +0100 Subject: [PATCH 101/143] Fix string constant options --- .../Utilities/LlvmIrGenerator/LlvmIrGenerator.cs | 4 ---- .../Utilities/LlvmIrGenerator/LlvmIrModule.cs | 2 +- .../Utilities/LlvmIrGenerator/LlvmIrVariable.cs | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs index d91d8faae50..d8656d09996 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs @@ -205,10 +205,6 @@ void WriteStrings (GeneratorWriteContext context) WriteCommentLine (context, $" '{info.Value}'"); } - if (!info.IsConstantStringLiteral) { - WriteCommentLine (context, $" '{info.Value}'"); - } - WriteGlobalVariableName (context, info); // Strings must always be local symbols, global variables will point to them diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs index ab38d7b2ecd..163e60ed51c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrModule.cs @@ -272,7 +272,7 @@ public LlvmIrGlobalVariable AddGlobalVariable (Type type, string name, object? v LlvmIrGlobalVariable ret; if (type == typeof(string)) { // The cast to `string?` is intentionally meant to throw if `value` type isn't a string. - ret = new LlvmIrStringVariable (name, new StringHolder ((string?)value)) { + ret = new LlvmIrStringVariable (name, new StringHolder ((string?)value), options) { Comment = comment, }; AddStringGlobalVariable ((LlvmIrStringVariable)ret); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs index 18c67db93a6..07badc4fd2c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrVariable.cs @@ -302,7 +302,7 @@ class LlvmIrStringVariable : LlvmIrGlobalVariable public bool IsConstantStringLiteral { get; } public LlvmIrStringVariable (string name, StringHolder value, LlvmIrVariableOptions? options = null) - : base (typeof(string), name, options ?? LlvmIrVariableOptions.GlobalConstexprString) + : base (typeof(string), name, options ?? LlvmIrVariableOptions.GlobalConstantStringPointer) { Value = value; Encoding = value.Encoding; From 9d6836c3a39adfef1eee6767d5f5085a1b06d6cc Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 12 Feb 2025 21:46:39 +0100 Subject: [PATCH 102/143] Hello world now runs. Caveats: * Trimming must be turned off * Typemaps don't work (everything is resolved dynamically) * Marshal methods must be turned off (they use MonoVM embedding API) --- .../Mono.Android.Runtime.csproj | 1 + .../Android.Runtime/AndroidRuntimeInternal.cs | 52 +++++- src/Mono.Android/Android.Runtime/JNIEnv.cs | 15 +- .../Android.Runtime/JNIEnvInit.cs | 2 + .../Android.Runtime/RuntimeNativeMethods.cs | 5 +- .../Utilities/LlvmIrGenerator/StringHolder.cs | 56 +++---- src/native/CMakeLists.txt | 2 + .../clr/host/generate-pinvoke-tables.cc | 11 +- src/native/clr/host/host-jni.cc | 1 + src/native/clr/host/host.cc | 154 ++++++++++++++++-- src/native/clr/host/internal-pinvokes.cc | 64 +++++++- src/native/clr/host/os-bridge.cc | 85 ++++++++++ src/native/clr/host/pinvoke-tables.include | 18 +- src/native/clr/include/host/host.hh | 35 ++-- src/native/clr/include/host/os-bridge.hh | 17 ++ src/native/clr/include/host/typemap.hh | 18 ++ .../include/runtime-base/internal-pinvokes.hh | 12 +- .../mono/monodroid/monodroid-glue-internal.hh | 1 - 18 files changed, 453 insertions(+), 96 deletions(-) create mode 100644 src/native/clr/include/host/typemap.hh diff --git a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj index 7612d7a2835..aac8b3bfe4c 100644 --- a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj +++ b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj @@ -52,6 +52,7 @@ + diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs b/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs index 141ff50f122..31d80445485 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs @@ -4,14 +4,64 @@ namespace Android.Runtime { + // The existence of InternalRuntimeTypeHolder and DotNetRuntimeTypeConverter classes looks weird, but + // we must handle a weird situation. AndroidRuntimeInternal needs to know in its static constructor + // what is the current runtime type, but it cannot query JNIEnvInit.RuntimeType, since that type lives + // in the Mono.Android assembly, while AndroidRuntimeInternal lives in Mono.Android.Runtime and it cannot + // access JNIEnvInit and Mono.Android.Runtime doesn't reference Mono.Android but Mono.Android **does** reference + // Mono.Android.Runtime and has access to its internals. + // + // Mono.Android.Runtime, also, includes several source files from Mono.Android - **both** assemblies + // include the same source files. In case of the DotNetRuntimeType enum, this declares two distinct types - one + // in Mono.Android and another in Mono.Android.Runtime, and so if JNIEnvInit.Initialize were to try to set the + // `DotNetRuntimeType RuntimeType;` field/property in either of the classes below, we'd get a compilation error + // to the effect of it being unable to cast `Android.Runtime.DotNetRuntimeType` to `Android.Runtime.DotNetRuntimeType`, + // which is usually as clear as mud :) + // + // To solve this and not duplicate code, the InternalRuntimeTypeHolder class is introduced which acts as a proxy since + // the AndroidRuntimeInternal static constructor must know the runtime type and JNIEnvInit.Initialize takes care of it by + // calling `SetRuntimeType` below long before AndroidRuntimeInternal cctor is invoked. + public static class InternalRuntimeTypeHolder + { + internal static DotNetRuntimeType RuntimeType = DotNetRuntimeType.Unknown; + + internal static void SetRuntimeType (uint runtimeType) + { + RuntimeType = DotNetRuntimeTypeConverter.Convert (runtimeType); + } + } + public static class AndroidRuntimeInternal { - internal static readonly Action mono_unhandled_exception = RuntimeNativeMethods.monodroid_debugger_unhandled_exception; + internal static readonly Action mono_unhandled_exception; #pragma warning disable CS0649 // Field is never assigned to. This field is assigned from monodroid-glue.cc. internal static volatile bool BridgeProcessing; // = false #pragma warning restore CS0649 // Field is never assigned to. + static AndroidRuntimeInternal () + { + mono_unhandled_exception = InternalRuntimeTypeHolder.RuntimeType switch { + DotNetRuntimeType.MonoVM => MonoUnhandledException, + DotNetRuntimeType.CoreCLR => CoreClrUnhandledException, + _ => throw new NotSupportedException ($"Internal error: runtime type {InternalRuntimeTypeHolder.RuntimeType} not supported") + }; + } + + static void CoreClrUnhandledException (Exception ex) + { + // TODO: Is this even needed on CoreCLR? + } + + // Needed when running under CoreCLR, which doesn't allow icalls/ecalls. Any method which contains any reference to + // an unregistered icall/ecall method will fail to JIT (even if the method isn't actually called). In this instance + // it affected the static constructor which tried to assign `RuntimeNativeMethods.monodroid_debugger_unhandled_exception` + // to `mono_unhandled_exception` at the top of the class. + static void MonoUnhandledException (Exception ex) + { + RuntimeNativeMethods.monodroid_debugger_unhandled_exception (ex); + } + public static void WaitForBridgeProcessing () { if (!BridgeProcessing) diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 01fb5c03572..9a62ac20bbc 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -414,6 +414,14 @@ internal static void LogTypemapTrace (StackTrace st) } } + // We need this proxy method because if `TypeManagedToJava` contained the call to `monodroid_typemap_managed_to_java` + // (which is an icall, or ecall in CoreCLR parlance), CoreCLR JIT would throw an exception, refusing to compile the + // method. The exception would be thrown even if the icall weren't called (e.g. hidden behind a runtime type check) + static unsafe IntPtr monovm_typemap_managed_to_java (Type type, byte* mvidptr) + { + return monodroid_typemap_managed_to_java (type, mvidptr); + } + internal static unsafe string? TypemapManagedToJava (Type type) { if (mvid_bytes == null) @@ -428,9 +436,14 @@ internal static void LogTypemapTrace (StackTrace st) mvid_data = mvid_bytes; } + RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"Current runtime type: {JNIEnvInit.RuntimeType}"); IntPtr ret; fixed (byte* mvidptr = mvid_data) { - ret = monodroid_typemap_managed_to_java (type, mvidptr); + ret = JNIEnvInit.RuntimeType switch { + DotNetRuntimeType.MonoVM => monovm_typemap_managed_to_java (type, mvidptr), + DotNetRuntimeType.CoreCLR => RuntimeNativeMethods.clr_typemap_managed_to_java (type.FullName, (IntPtr)mvidptr), + _ => throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported") + }; } if (ret == IntPtr.Zero) { diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs index 8c4ed9c5b7b..1e80e1f34b7 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs @@ -90,7 +90,9 @@ internal static void InitializeJniRuntime (JniRuntime runtime) [UnmanagedCallersOnly] internal static unsafe void Initialize (JnienvInitializeArgs* args) { + // This looks weird, see comments in RuntimeTypeInternal.cs RuntimeType = DotNetRuntimeTypeConverter.Convert (args->runtimeType); + InternalRuntimeTypeHolder.SetRuntimeType (args->runtimeType); IntPtr total_timing_sequence = IntPtr.Zero; IntPtr partial_timing_sequence = IntPtr.Zero; diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index 8c3edcf1045..c80a5dd1a09 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -6,7 +6,7 @@ namespace Android.Runtime { - // Values must be identical to those in src/monodroid/jni/monodroid-glue-internal.hh + // NOTE: Keep this in sync with the native side in src/native/common/include/managed-interface.hh [Flags] enum TraceKind : uint { @@ -89,6 +89,9 @@ internal static class RuntimeNativeMethods [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_max_gref_get (); + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr clr_typemap_managed_to_java (string fullName, IntPtr mvid); + [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs index cbcfd02c9d8..1043f1dc145 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/StringHolder.cs @@ -34,15 +34,7 @@ public static StringHolder AsHolder (object? value, LlvmIrStringEncoding encodin return holder; } - public int CompareTo (object obj) - { - var holder = obj as StringHolder; - if (holder == null) { - return 1; - } - - return CompareTo (holder); - } + public int CompareTo (object obj) => CompareTo (obj as StringHolder); public int CompareTo (StringHolder? other) { @@ -83,15 +75,7 @@ public override int GetHashCode () return hc ^ Encoding.GetHashCode (); } - public override bool Equals (object obj) - { - var holder = obj as StringHolder; - if (holder == null) { - return false; - } - - return Equals (holder); - } + public override bool Equals (object obj) => Equals (obj as StringHolder); public bool Equals (StringHolder? other) { @@ -103,22 +87,22 @@ public bool Equals (StringHolder? other) } public static bool operator > (StringHolder a, StringHolder b) - { - return a.CompareTo (b) > 0; - } - - public static bool operator < (StringHolder a, StringHolder b) - { - return a.CompareTo (b) < 0; - } - - public static bool operator >= (StringHolder a, StringHolder b) - { - return a.CompareTo (b) >= 0; - } - - public static bool operator <= (StringHolder a, StringHolder b) - { - return a.CompareTo (b) <= 0; - } + { + return a.CompareTo (b) > 0; + } + + public static bool operator < (StringHolder a, StringHolder b) + { + return a.CompareTo (b) < 0; + } + + public static bool operator >= (StringHolder a, StringHolder b) + { + return a.CompareTo (b) >= 0; + } + + public static bool operator <= (StringHolder a, StringHolder b) + { + return a.CompareTo (b) <= 0; + } } diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index a72c5672b3a..daabbae428f 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -220,6 +220,8 @@ set(JAVA_INTEROP_INCLUDE_DIR ${JAVA_INTEROP_SRC_PATH}) set(CONSTEXPR_XXH3_DIR "${EXTERNAL_DIR}/constexpr-xxh3") set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") +include_directories(common/include) + if(IS_CLR_RUNTIME) set(XA_RUNTIME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/clr/include) diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index 3db291962c3..834574731ab 100644 --- a/src/native/clr/host/generate-pinvoke-tables.cc +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -42,7 +42,7 @@ const std::vector internal_pinvoke_names = { // "monodroid_dylib_mono_new", // "monodroid_embedded_assemblies_set_assemblies_prefix", // "monodroid_fopen", -// "monodroid_free", + "monodroid_free", // "_monodroid_freeifaddrs", // "_monodroid_gc_wait_for_bridge_processing", // "_monodroid_get_dns_servers", @@ -53,10 +53,10 @@ const std::vector internal_pinvoke_names = { // "_monodroid_get_network_interface_up_state", // "monodroid_get_system_property", "_monodroid_gref_get", -// "_monodroid_gref_log", -// "_monodroid_gref_log_delete", + "_monodroid_gref_log", + "_monodroid_gref_log_delete", "_monodroid_gref_log_new", -// "monodroid_log", + "monodroid_log", // "monodroid_log_traces", // "_monodroid_lookup_replacement_type", // "_monodroid_lookup_replacement_method_info", @@ -69,7 +69,8 @@ const std::vector internal_pinvoke_names = { // "_monodroid_timezone_get_default_id", // "monodroid_timing_start", // "monodroid_timing_stop", -// "monodroid_TypeManager_get_java_class_name", + "monodroid_TypeManager_get_java_class_name", + "clr_typemap_managed_to_java", // "_monodroid_weak_gref_delete", // "_monodroid_weak_gref_get", // "_monodroid_weak_gref_new", diff --git a/src/native/clr/host/host-jni.cc b/src/native/clr/host/host-jni.cc index 349bd178221..21dc862d5cf 100644 --- a/src/native/clr/host/host-jni.cc +++ b/src/native/clr/host/host-jni.cc @@ -25,6 +25,7 @@ JNICALL Java_mono_android_Runtime_dumpTimingData ([[maybe_unused]] JNIEnv *env, JNIEXPORT void JNICALL Java_mono_android_Runtime_register (JNIEnv *env, [[maybe_unused]] jclass klass, jstring managedType, jclass nativeClass, jstring methods) { + Host::Java_mono_android_Runtime_register (env, managedType, nativeClass, methods); } JNIEXPORT void JNICALL diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 0743bc669ea..2b7a4f97285 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -118,9 +118,46 @@ void Host::create_xdg_directories_and_environment (jstring_wrapper &homeDir) noe create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME); } +[[gnu::always_inline]] +auto Host::create_delegate ( + std::string_view const& assembly_name, std::string_view const& type_name, + std::string_view const& method_name) noexcept -> void* +{ + void *delegate = nullptr; + int hr = coreclr_create_delegate ( + clr_host, + domain_id, + assembly_name.data (), + type_name.data (), + method_name.data (), + &delegate + ); + log_debug (LOG_ASSEMBLY, + "{} delegate creation result == {:x}; delegate == {:p}", + Constants::JNIENVINIT_FULL_TYPE_NAME, + static_cast(hr), + delegate + ); + + // TODO: make S_OK & friends known to us + if (hr != 0 /* S_OK */) { + Helpers::abort_application ( + LOG_DEFAULT, + std::format ( + "Failed to create delegate for {}.{}.{} (result == {:x})", + assembly_name, + type_name, + method_name, + hr) + ); + } + + return delegate; +} + void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeClass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, - jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) + jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) noexcept { Logger::init_logging_categories (); @@ -166,9 +203,15 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl ); log_debug (LOG_ASSEMBLY, "CoreCLR init result == {:x}; clr_host == {:p}; domain ID == {}", static_cast(hr), clr_host, domain_id); // TODO: make S_OK & friends known to us - // if (hr != S_OK) { - // } - log_write (LOG_DEFAULT, LogLevel::Info, "CoreCLR initialization routine returned"); + if (hr != 0 /* S_OK */) { + Helpers::abort_application ( + LOG_DEFAULT, + std::format ( + "Failed to initialize CoreCLR. Error code: {:x}", + static_cast(hr) + ) + ); + } abort_unless ( clr_host != nullptr, @@ -178,6 +221,7 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl ); struct JnienvInitializeArgs init = {}; + init.runtimeType = RuntimeTypeCoreCLR; init.javaVm = jvm; init.env = env; init.logCategories = log_categories; @@ -216,25 +260,33 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl native_to_managed_index = internal_timing->start_event (TimingEventKind::NativeToManagedTransition); } - log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.Initialize", Constants::JNIENVINIT_FULL_TYPE_NAME); void *delegate = nullptr; - hr = coreclr_create_delegate ( - clr_host, - domain_id, - Constants::MONO_ANDROID_ASSEMBLY_NAME.data (), - Constants::JNIENVINIT_FULL_TYPE_NAME.data (), - "Initialize", - &delegate + log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.RegisterJniNatives", Constants::JNIENVINIT_FULL_TYPE_NAME); + delegate = create_delegate (Constants::MONO_ANDROID_ASSEMBLY_NAME, Constants::JNIENVINIT_FULL_TYPE_NAME, "RegisterJniNatives"sv); + jnienv_register_jni_natives = reinterpret_cast (delegate); + abort_unless ( + jnienv_register_jni_natives != nullptr, + [] { + return detail::_format_message ( + "Failed to obtain unmanaged-callers-only pointer to the %s.%s.RegisterJniNatives method.", + Constants::MONO_ANDROID_ASSEMBLY_NAME, + Constants::JNIENVINIT_FULL_TYPE_NAME + ); + } ); - log_debug (LOG_ASSEMBLY, "Delegate creation result == {:x}; delegate == {:p}", static_cast(hr), delegate); - // TODO: make S_OK & friends known to us - // if (hr != S_OK) { - // } + log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.Initialize", Constants::JNIENVINIT_FULL_TYPE_NAME); + delegate = create_delegate (Constants::MONO_ANDROID_ASSEMBLY_NAME, Constants::JNIENVINIT_FULL_TYPE_NAME, "Initialize"sv); auto initialize = reinterpret_cast (delegate); abort_unless ( initialize != nullptr, - "Failed to obtain unmanaged-callers-only pointer to the Android.Runtime.JNIEnvInit.Initialize method." + [] { + return detail::_format_message ( + "Failed to obtain unmanaged-callers-only pointer to the %s.%s.Initialize method.", + Constants::MONO_ANDROID_ASSEMBLY_NAME, + Constants::JNIENVINIT_FULL_TYPE_NAME + ); + } ); initialize (&init); @@ -247,10 +299,78 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl } } +void Host::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods) noexcept +{ + size_t total_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + total_time_index = internal_timing->start_event (TimingEventKind::RuntimeRegister); + } + + jsize managedType_len = env->GetStringLength (managedType); + const jchar *managedType_ptr = env->GetStringChars (managedType, nullptr); + int methods_len = env->GetStringLength (methods); + const jchar *methods_ptr = env->GetStringChars (methods, nullptr); + + // TODO: must attach thread to the runtime here + jnienv_register_jni_natives (managedType_ptr, managedType_len, nativeClass, methods_ptr, methods_len); + + env->ReleaseStringChars (methods, methods_ptr); + env->ReleaseStringChars (managedType, managedType_ptr); + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing->end_event (total_time_index, true /* uses_more_info */); + + dynamic_local_string type; + const char *mt_ptr = env->GetStringUTFChars (managedType, nullptr); + type.assign (mt_ptr, strlen (mt_ptr)); + env->ReleaseStringUTFChars (managedType, mt_ptr); + + internal_timing->add_more_info (total_time_index, type); + } +} + +auto Host::get_java_class_name_for_TypeManager (jclass klass) noexcept -> char* +{ + if (klass == nullptr || Class_getName == nullptr) { + return nullptr; + } + + JNIEnv *env = OSBridge::ensure_jnienv (); + jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); + if (name == nullptr) { + log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); + return nullptr; + } + + const char *mutf8 = env->GetStringUTFChars (name, nullptr); + if (mutf8 == nullptr) { + log_error (LOG_DEFAULT, "Failed to convert Java class name to UTF8 (out of memory?)"sv); + env->DeleteLocalRef (name); + return nullptr; + } + char *ret = strdup (mutf8); + + env->ReleaseStringUTFChars (name, mutf8); + env->DeleteLocalRef (name); + + char *dot = strchr (ret, '.'); + while (dot != nullptr) { + *dot = '/'; + dot = strchr (dot + 1, '.'); + } + + return ret; +} + auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint { log_write (LOG_DEFAULT, LogLevel::Info, "Host OnLoad"); jvm = vm; + + JNIEnv *env = nullptr; + vm->GetEnv ((void**)&env, JNI_VERSION_1_6); + OSBridge::initialize_on_onload (vm, env); + AndroidSystem::init_max_gref_count (); return JNI_VERSION_1_6; } diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 8193e911599..be2ab2185d7 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -1,16 +1,72 @@ +#include #include +#include #include using namespace xamarin::android; -int -_monodroid_gref_get () +int _monodroid_gref_get () noexcept { return OSBridge::get_gc_gref_count (); } -int -_monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) +void _monodroid_gref_log (const char *message) noexcept +{ +} + +int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept { return OSBridge::_monodroid_gref_log_new (curHandle, curType, newHandle, newType, threadName, threadId, from, from_writable); } + +void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept +{ +} + +const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept +{ + return TypeMap::typemap_managed_to_java (typeName, mvid); +} + +void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept +{ + switch (level) { + case LogLevel::Verbose: + case LogLevel::Debug: + log_debug_nocheck (category, std::string_view { message }); + break; + + case LogLevel::Info: + log_info_nocheck (category, std::string_view { message }); + break; + + case LogLevel::Warn: + case LogLevel::Silent: // warn is always printed + log_warn (category, std::string_view { message }); + break; + + case LogLevel::Error: + log_error (category, std::string_view { message }); + break; + + case LogLevel::Fatal: + log_fatal (category, std::string_view { message }); + break; + + default: + case LogLevel::Unknown: + case LogLevel::Default: + log_info_nocheck (category, std::string_view { message }); + break; + } +} + +char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept +{ + return Host::get_java_class_name_for_TypeManager (klass); +} + +void monodroid_free (void *ptr) noexcept +{ + free (ptr); +} diff --git a/src/native/clr/host/os-bridge.cc b/src/native/clr/host/os-bridge.cc index 5296893e8f7..a2ec0492340 100644 --- a/src/native/clr/host/os-bridge.cc +++ b/src/native/clr/host/os-bridge.cc @@ -6,6 +6,30 @@ using namespace xamarin::android; +void OSBridge::initialize_on_onload (JavaVM *vm, JNIEnv *env) noexcept +{ + abort_if_invalid_pointer_argument (env, "env"); + abort_if_invalid_pointer_argument (vm, "vm"); + + jvm = vm; + // jclass lref = env->FindClass ("java/lang/Runtime"); + // jmethodID Runtime_getRuntime = env->GetStaticMethodID (lref, "getRuntime", "()Ljava/lang/Runtime;"); + + // Runtime_gc = env->GetMethodID (lref, "gc", "()V"); + // Runtime_instance = lref_to_gref (env, env->CallStaticObjectMethod (lref, Runtime_getRuntime)); + // env->DeleteLocalRef (lref); + // lref = env->FindClass ("java/lang/ref/WeakReference"); + // weakrefClass = reinterpret_cast (env->NewGlobalRef (lref)); + // env->DeleteLocalRef (lref); + // weakrefCtor = env->GetMethodID (weakrefClass, "", "(Ljava/lang/Object;)V"); + // weakrefGet = env->GetMethodID (weakrefClass, "get", "()Ljava/lang/Object;"); + + // abort_unless ( + // weakrefClass != nullptr && weakrefCtor != nullptr && weakrefGet != nullptr, + // "Failed to look up required java.lang.ref.WeakReference members" + // ); +} + void OSBridge::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept { abort_if_invalid_pointer_argument (env, "env"); @@ -71,6 +95,20 @@ void OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) } while (c); } +void OSBridge::_monodroid_gref_log (const char *message) noexcept +{ + if (Logger::gref_to_logcat ()) { + log_debug (LOG_GREF, "{}", optional_string (message)); + } + + if (Logger::gref_log () == nullptr) { + return; + } + + fprintf (Logger::gref_log (), "%s", optional_string (message)); + fflush (Logger::gref_log ()); +} + auto OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept -> int { int c = _monodroid_gref_inc (); @@ -124,3 +162,50 @@ auto OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject fflush (Logger::gref_log ()); return c; } + +void OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept +{ + int c = _monodroid_gref_dec (); + if ((log_categories & LOG_GREF) == 0) { + return; + } + + log_info (LOG_GREF, + "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + c, + gc_weak_gref_count, + reinterpret_cast(handle), + type, + optional_string (threadName), + threadId + ); + if (Logger::gref_to_logcat ()) { + if (from_writable) { + _write_stack_trace (nullptr, const_cast(from), LOG_GREF); + } else { + log_info (LOG_GREF, "{}", optional_string (from)); + } + } + + if (Logger::gref_log () == nullptr) { + return; + } + + fprintf (Logger::gref_log (), + "-g- grefc %i gwrefc %i handle %p/%c from thread '%s'(%i)\n", + c, + gc_weak_gref_count, + handle, + type, + optional_string (threadName), + threadId + ); + + if (from_writable) { + _write_stack_trace (Logger::gref_log (), const_cast(from)); + } else { + fprintf (Logger::gref_log(), "%s\n", optional_string (from)); + } + + fflush (Logger::gref_log ()); +} diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include index 49e1dc4059f..491bb5ee7e6 100644 --- a/src/native/clr/host/pinvoke-tables.include +++ b/src/native/clr/host/pinvoke-tables.include @@ -11,9 +11,15 @@ namespace { #if INTPTR_MAX == INT64_MAX //64-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ {0x4b1956138764939a, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, + {0x9187e6bc6294cacf, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, + {0xa7f58f3ee428cc6b, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, + {0xae3df96dda0143bd, "_monodroid_gref_log", reinterpret_cast(&_monodroid_gref_log)}, + {0xb8306f71b963cd3d, "monodroid_log", reinterpret_cast(&monodroid_log)}, {0xd1e121b94ea63f2e, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, + {0xd5151b00eb33d85e, "monodroid_TypeManager_get_java_class_name", reinterpret_cast(&monodroid_TypeManager_get_java_class_name)}, + {0xf41c48df6f9be476, "monodroid_free", reinterpret_cast(&monodroid_free)}, }}; //64-bit DotNet p/invoke table @@ -506,9 +512,15 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x18 constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; #else //32-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ + {0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast(&monodroid_TypeManager_get_java_class_name)}, + {0x656e00bd, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, + {0xa04e5d1c, "monodroid_free", reinterpret_cast(&monodroid_free)}, {0xb02468aa, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, {0xbe8d7701, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, + {0xc5146c54, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, + {0xe7e77ca5, "_monodroid_gref_log", reinterpret_cast(&_monodroid_gref_log)}, + {0xfa4e32ca, "monodroid_log", reinterpret_cast(&monodroid_log)}, }}; //32-bit DotNet p/invoke table @@ -1001,6 +1013,6 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93 constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a; #endif -constexpr size_t internal_pinvokes_count = 2; +constexpr size_t internal_pinvokes_count = 8; constexpr size_t dotnet_pinvokes_count = 477; } // end of anonymous namespace diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 4cffc3dfbe3..7c47bb8a337 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -8,39 +8,19 @@ #include "../runtime-base/jni-wrappers.hh" #include "../runtime-base/timing.hh" #include "../shared/log_types.hh" +#include "managed-interface.hh" namespace xamarin::android { - // NOTE: Keep this in sync with managed side in src/Mono.Android/Android.Runtime/JNIEnvInit.cs - struct JnienvInitializeArgs - { - JavaVM *javaVm; - JNIEnv *env; - jobject grefLoader; - jmethodID Loader_loadClass; - jclass grefClass; - unsigned int logCategories; - int version; - int grefGcThreshold; - jobject grefIGCUserPeer; - int isRunningOnDesktop; - uint8_t brokenExceptionTransitions; - int packageNamingPolicy; - uint8_t boundExceptionType; - int jniAddNativeMethodRegistrationAttributePresent; - bool jniRemappingInUse; - bool marshalMethodsEnabled; - jobject grefGCUserPeerable; - }; - class Host { - using jnienv_initialize_fn = void (*) (JnienvInitializeArgs*); - public: static auto Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint; static void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset, jobject loader, - jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks); + jobjectArray assembliesJava, jboolean isEmulator, jboolean haveSplitApks) noexcept; + static void Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods) noexcept; + + static auto get_java_class_name_for_TypeManager (jclass klass) noexcept -> char*; static auto get_timing () -> Timing* { @@ -58,11 +38,16 @@ namespace xamarin::android { static const void* clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept; static void clr_error_writer (const char *message) noexcept; + static auto create_delegate ( + std::string_view const& assembly_name, std::string_view const& type_name, + std::string_view const& method_name) noexcept -> void*; + private: static inline void *clr_host = nullptr; static inline unsigned int domain_id = 0; static inline std::unique_ptr _timing{}; static inline bool found_assembly_store = false; + static inline jnienv_register_jni_natives_fn jnienv_register_jni_natives = nullptr; static inline JavaVM *jvm = nullptr; static inline jmethodID Class_getName = nullptr; diff --git a/src/native/clr/include/host/os-bridge.hh b/src/native/clr/include/host/os-bridge.hh index 50ee3c20166..0bce2a180fb 100644 --- a/src/native/clr/include/host/os-bridge.hh +++ b/src/native/clr/include/host/os-bridge.hh @@ -10,6 +10,7 @@ namespace xamarin::android { class OSBridge { public: + static void initialize_on_onload (JavaVM *vm, JNIEnv *env) noexcept; static void initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept; static auto lref_to_gref (JNIEnv *env, jobject lref) noexcept -> jobject; @@ -23,7 +24,22 @@ namespace xamarin::android { return gc_weak_gref_count; } + static void _monodroid_gref_log (const char *message) noexcept; static auto _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept -> int; + static void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; + + static auto ensure_jnienv () noexcept -> JNIEnv* + { + JNIEnv *env = nullptr; + jvm->GetEnv ((void**)&env, JNI_VERSION_1_6); + if (env == nullptr) { + // TODO: attach to the runtime thread here + jvm->GetEnv ((void**)&env, JNI_VERSION_1_6); + abort_unless (env != nullptr, "Unable to get a valid pointer to JNIEnv"); + } + + return env; + } private: static auto _monodroid_gref_inc () noexcept -> int; @@ -32,6 +48,7 @@ namespace xamarin::android { static void _write_stack_trace (FILE *to, char *from, LogCategories = LOG_NONE) noexcept; private: + static inline JavaVM *jvm = nullptr; static inline jclass GCUserPeer_class = nullptr; static inline jmethodID GCUserPeer_ctor = nullptr; diff --git a/src/native/clr/include/host/typemap.hh b/src/native/clr/include/host/typemap.hh new file mode 100644 index 00000000000..518e5f333d4 --- /dev/null +++ b/src/native/clr/include/host/typemap.hh @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "../runtime-base/logger.hh" + +namespace xamarin::android { + class TypeMap + { + public: + static auto typemap_managed_to_java ([[maybe_unused]] const char *typeName, [[maybe_unused]] const uint8_t *mvid) noexcept -> const char* + { + log_warn (LOG_ASSEMBLY, "{} not implemented yet", __PRETTY_FUNCTION__); + log_warn (LOG_ASSEMBLY, " asked for '{}'", optional_string (typeName)); + + return nullptr; + } + }; +} diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index 72a0d9dcc32..f2aa3792369 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -2,5 +2,13 @@ #include -int _monodroid_gref_get (); -int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable); +#include "logger.hh" + +int _monodroid_gref_get () noexcept; +void _monodroid_gref_log (const char *message) noexcept; +int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept; +void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; +const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept; +void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; +char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; +void monodroid_free (void *ptr) noexcept; diff --git a/src/native/mono/monodroid/monodroid-glue-internal.hh b/src/native/mono/monodroid/monodroid-glue-internal.hh index 2708ac58205..2d4f84276b8 100644 --- a/src/native/mono/monodroid/monodroid-glue-internal.hh +++ b/src/native/mono/monodroid/monodroid-glue-internal.hh @@ -13,7 +13,6 @@ #include #include "monodroid-dl.hh" #include -#include #include #include From ee6195fa7693d03f3d7a43e4c971672fca17d8b5 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 13 Feb 2025 13:34:07 +0100 Subject: [PATCH 103/143] WIP for CoreCLR typemaps --- .../Utilities/TypeMapGenerator.cs | 2 +- ...appingReleaseNativeAssemblyGeneratorCLR.cs | 160 ++++-------------- src/native/clr/include/xamarin-app.hh | 26 ++- .../xamarin-app-stub/application_dso_stub.cc | 10 +- 4 files changed, 54 insertions(+), 144 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs index 32ee751b0c2..7a39539e258 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs @@ -448,7 +448,7 @@ bool GenerateRelease (bool skipJniAddNativeMethodRegistrationAttributeScan, stri LLVMIR.LlvmIrComposer composer = runtime switch { AndroidRuntime.MonoVM => new TypeMappingReleaseNativeAssemblyGenerator (log, new NativeTypeMappingData (log, modules)), - AndroidRuntime.CoreCLR => throw new NotImplementedException ("CoreCLR support not implemented yet"), + AndroidRuntime.CoreCLR => new TypeMappingReleaseNativeAssemblyGeneratorCLR (log, new NativeTypeMappingData (log, modules)), _ => throw new NotSupportedException ($"Internal error: unsupported runtime {runtime}") }; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs index 5c62f0df88f..420a7bf31c4 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs @@ -58,61 +58,19 @@ public override ulong GetBufferSize (object data, string fieldName) } } - sealed class TypeMapJavaContextDataProvider : NativeAssemblerStructContextDataProvider - { - public override string GetComment (object data, string fieldName) - { - var java_map_entry = EnsureType (data); - - if (String.Compare ("managed_type_name_index", fieldName, StringComparison.Ordinal) == 0) { - return $" managed type name: {java_map_entry.ManagedTypeName}"; - } - - if (String.Compare ("java_name_index", fieldName, StringComparison.Ordinal) == 0) { - return $" Java type name: {java_map_entry.JavaName}"; - } - - return String.Empty; - } - }; - - sealed class TypeMapModuleEntryContextDataProvider : NativeAssemblerStructContextDataProvider - { - public override string GetComment (object data, string fieldName) - { - var module_map_entry = EnsureType (data); - - if (String.Compare ("managed_type_name_hash_32", fieldName, StringComparison.Ordinal) == 0 || - String.Compare ("managed_type_name_hash_64", fieldName, StringComparison.Ordinal) == 0) { - return $" managed type name: {module_map_entry.ManagedTypeName}"; - } - - if (String.Compare ("java_map_index", fieldName, StringComparison.Ordinal) == 0) { - return $" Java type name: {module_map_entry.JavaTypeMapEntry.JavaName}"; - } - - return String.Empty; - } - }; - // Order of fields and their type must correspond *exactly* to that in // src/native/clr/include/xamarin-app.hh TypeMapModuleEntry structure - [NativeAssemblerStructContextDataProvider (typeof (TypeMapModuleEntryContextDataProvider))] sealed class TypeMapModuleEntry { [NativeAssembler (Ignore = true)] public TypeMapJava JavaTypeMapEntry; - [NativeAssembler (Ignore = true)] - public string ManagedTypeName; - - [NativeAssembler (UsesDataProvider = true, ValidTarget = NativeAssemblerValidTarget.ThirtyTwoBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + [NativeAssembler (ValidTarget = NativeAssemblerValidTarget.ThirtyTwoBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] public uint managed_type_name_hash_32; - [NativeAssembler (UsesDataProvider = true, ValidTarget = NativeAssemblerValidTarget.SixtyFourBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + [NativeAssembler (ValidTarget = NativeAssemblerValidTarget.SixtyFourBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] public ulong managed_type_name_hash_64; - [NativeAssembler (UsesDataProvider = true)] public uint java_map_index; } @@ -153,30 +111,25 @@ sealed class TypeMapModule // Order of fields and their type must correspond *exactly* to that in // src/native/clr/include/xamarin-app.hh TypeMapJava structure - [NativeAssemblerStructContextDataProvider (typeof (TypeMapJavaContextDataProvider))] sealed class TypeMapJava { [NativeAssembler (Ignore = true)] public string JavaName; - [NativeAssembler (Ignore = true)] - public string ManagedTypeName; - [NativeAssembler (Ignore = true)] public uint JavaNameHash32; [NativeAssembler (Ignore = true)] public ulong JavaNameHash64; - public uint module_index; - - [NativeAssembler (UsesDataProvider = true)] - public uint managed_type_name_index; + [NativeAssembler (Ignore = true)] + public uint ManagedNameHash32; - [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] - public uint managed_type_token_id; + [NativeAssembler (Ignore = true)] + public ulong ManagedNameHash64; - [NativeAssembler (UsesDataProvider = true)] + public uint module_index; + public uint managed_type_name_index; public uint java_name_index; } @@ -213,7 +166,6 @@ sealed class ConstructionState public List> MapModules; public Dictionary JavaTypesByName; public List JavaNames; - public List ManagedTypeNames; public List> JavaMap; public List AllModulesData; public List AssemblyNames; @@ -234,19 +186,6 @@ public TypeMappingReleaseNativeAssemblyGeneratorCLR (TaskLoggingHelper log, Nati this.mappingData = mappingData ?? throw new ArgumentNullException (nameof (mappingData)); javaNameHash32Comparer = new JavaNameHash32Comparer (); javaNameHash64Comparer = new JavaNameHash64Comparer (); - - // Unfortunate, but we have to fix this up before proceeding - foreach (TypeMapGenerator.ModuleReleaseData module in mappingData.Modules) { - foreach (TypeMapGenerator.TypeMapReleaseEntry entry in module.Types) { - if (entry.ManagedTypeName.IndexOf ('/') < 0) { - continue; - } - - // CoreCLR will request for subtypes with the `+` level separator instead of - // the `/` one. - entry.ManagedTypeName = entry.ManagedTypeName.Replace ('/', '+'); - } - } } protected override void Construct (LlvmIrModule module) @@ -287,7 +226,7 @@ protected override void Construct (LlvmIrModule module) foreach (ModuleMapData mmd in cs.AllModulesData) { var mmdVar = new LlvmIrGlobalVariable (mmd.Entries, mmd.SymbolLabel, LlvmIrVariableOptions.LocalConstant) { - BeforeWriteCallback = SortEntriesAndUpdateJavaIndexes, + BeforeWriteCallback = UpdateJavaIndexes, BeforeWriteCallbackCallerState = cs, }; module.Add (mmdVar); @@ -295,27 +234,16 @@ protected override void Construct (LlvmIrModule module) module.AddGlobalVariable ("java_to_managed_map", cs.JavaMap, LlvmIrVariableOptions.GlobalConstant, " Java to managed map"); module.AddGlobalVariable ("java_type_names", cs.JavaNames, LlvmIrVariableOptions.GlobalConstant, " Java type names"); - module.AddGlobalVariable ("managed_type_names", cs.ManagedTypeNames, LlvmIrVariableOptions.GlobalConstant, " Managed type names"); module.AddGlobalVariable ("managed_assembly_names", cs.AssemblyNames, LlvmIrVariableOptions.GlobalConstant, " Managed assembly names"); } - void SortEntriesAndUpdateJavaIndexes (LlvmIrVariable variable, LlvmIrModuleTarget target, object? callerState) + void UpdateJavaIndexes (LlvmIrVariable variable, LlvmIrModuleTarget target, object? callerState) { ConstructionState cs = EnsureConstructionState (callerState); LlvmIrGlobalVariable gv = EnsureGlobalVariable (variable); IComparer> hashComparer = target.Is64Bit ? javaNameHash64Comparer : javaNameHash32Comparer; var entries = (List>)variable.Value; - if (target.Is64Bit) { - entries.Sort ( - (StructureInstance a, StructureInstance b) => a.Instance.managed_type_name_hash_64.CompareTo (b.Instance.managed_type_name_hash_64) - ); - } else { - entries.Sort ( - (StructureInstance a, StructureInstance b) => a.Instance.managed_type_name_hash_32.CompareTo (b.Instance.managed_type_name_hash_32) - ); - } - foreach (StructureInstance entry in entries) { entry.Instance.java_map_index = GetJavaEntryIndex (entry.Instance.JavaTypeMapEntry); } @@ -381,35 +309,16 @@ ConstructionState EnsureConstructionState (object? callerState) return cs; } - uint GetEntryIndex (string entryValue, Dictionary seenCache, List entryList) - { - if (!seenCache.TryGetValue (entryValue, out uint assemblyNameIndex)) { - entryList.Add (entryValue); - assemblyNameIndex = (uint)(entryList.Count - 1); - seenCache.Add (entryValue, assemblyNameIndex); - } - - return assemblyNameIndex; - } - void InitJavaMap (ConstructionState cs) { - var seenManagedTypeNames = new Dictionary (StringComparer.Ordinal); cs.JavaMap = new List> (); - cs.ManagedTypeNames = new List (); - TypeMapJava map_entry; foreach (TypeMapGenerator.TypeMapReleaseEntry entry in mappingData.JavaTypes) { - string assemblyName = mappingData.Modules[entry.ModuleIndex].AssemblyName; - uint managedTypeNameIndex = GetEntryIndex (entry.ManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); cs.JavaNames.Add (entry.JavaName); map_entry = new TypeMapJava { - ManagedTypeName = cs.ManagedTypeNames[(int)managedTypeNameIndex], - module_index = (uint)entry.ModuleIndex, // UInt32.MaxValue, - managed_type_name_index = managedTypeNameIndex, - managed_type_token_id = entry.Token, +// type_token_id = entry.SkipInJavaToManaged ? 0 : entry.Token, java_name_index = (uint)(cs.JavaNames.Count - 1), JavaName = entry.JavaName, }; @@ -422,11 +331,16 @@ void InitJavaMap (ConstructionState cs) void InitMapModules (ConstructionState cs) { var seenAssemblyNames = new Dictionary (StringComparer.OrdinalIgnoreCase); + var assemblyNames = new List (); cs.MapModules = new List> (); - cs.AssemblyNames = new List (); foreach (TypeMapGenerator.ModuleReleaseData data in mappingData.Modules) { - uint assemblyNameIndex = GetEntryIndex (data.AssemblyName, seenAssemblyNames, cs.AssemblyNames); + if (!seenAssemblyNames.TryGetValue (data.AssemblyName, out uint assemblyNameIndex)) { + assemblyNames.Add (data.AssemblyName); + assemblyNameIndex = (uint)(assemblyNames.Count - 1); + seenAssemblyNames.Add (data.AssemblyName, assemblyNameIndex); + } + string mapName = $"module{moduleCounter++}_managed_to_java"; string duplicateMapName; @@ -441,7 +355,7 @@ void InitMapModules (ConstructionState cs) MapSymbolName = mapName, DuplicateMapSymbolName = duplicateMapName.Length == 0 ? null : duplicateMapName, Data = data, - AssemblyName = cs.AssemblyNames[(int)assemblyNameIndex], + AssemblyName = assemblyNames[(int)assemblyNameIndex], module_uuid = data.MvidBytes, entry_count = (uint)data.Types.Length, @@ -451,6 +365,7 @@ void InitMapModules (ConstructionState cs) cs.MapModules.Add (new StructureInstance (typeMapModuleStructureInfo, map_module)); } + cs.AssemblyNames = assemblyNames; } void MapStructures (LlvmIrModule module) @@ -463,23 +378,20 @@ void MapStructures (LlvmIrModule module) void PrepareMapModuleData (string moduleDataSymbolLabel, IEnumerable moduleEntries, ConstructionState cs) { var mapModuleEntries = new List> (); - foreach (TypeMapGenerator.TypeMapReleaseEntry entry in moduleEntries) { - if (!cs.JavaTypesByName.TryGetValue (entry.JavaName, out TypeMapJava javaType)) { - throw new InvalidOperationException ($"Internal error: Java type '{entry.JavaName}' not found in cache"); - } - - var map_entry = new TypeMapModuleEntry { - JavaTypeMapEntry = javaType, - ManagedTypeName = entry.ManagedTypeName, - - managed_type_name_hash_32 = (uint)MonoAndroidHelper.GetXxHash (entry.ManagedTypeName, is64Bit: false), - managed_type_name_hash_64 = MonoAndroidHelper.GetXxHash (entry.ManagedTypeName, is64Bit: true), - java_map_index = UInt32.MaxValue, // will be set later, when the target is known - }; - mapModuleEntries.Add (new StructureInstance (typeMapModuleEntryStructureInfo, map_entry)); - } - -// mapModuleEntries.Sort ((StructureInstance a, StructureInstance b) => a.Instance.type_token_id.CompareTo (b.Instance.type_token_id)); + // foreach (TypeMapGenerator.TypeMapReleaseEntry entry in moduleEntries) { + // if (!cs.JavaTypesByName.TryGetValue (entry.JavaName, out TypeMapJava javaType)) { + // throw new InvalidOperationException ($"Internal error: Java type '{entry.JavaName}' not found in cache"); + // } + + // var map_entry = new TypeMapModuleEntry { + // JavaTypeMapEntry = javaType, + // type_token_id = entry.Token, + // java_map_index = UInt32.MaxValue, // will be set later, when the target is known + // }; + // mapModuleEntries.Add (new StructureInstance (typeMapModuleEntryStructureInfo, map_entry)); + // } + + // mapModuleEntries.Sort ((StructureInstance a, StructureInstance b) => a.Instance.type_token_id.CompareTo (b.Instance.type_token_id)); cs.AllModulesData.Add (new ModuleMapData (moduleDataSymbolLabel, mapModuleEntries)); } @@ -507,10 +419,10 @@ void HashJavaNames (ConstructionState cs) TypeMapJava entry = cs.JavaMap[i].Instance; // The cast is safe, xxHash will return a 32-bit value which (for convenience) was upcast to 64-bit - entry.JavaNameHash32 = (uint)TypeMapHelper.HashJavaNameForCLR (entry.JavaName, is64Bit: false); + entry.JavaNameHash32 = (uint)TypeMapHelper.HashJavaName (entry.JavaName, is64Bit: false); hashes32.Add (entry.JavaNameHash32); - entry.JavaNameHash64 = TypeMapHelper.HashJavaNameForCLR (entry.JavaName, is64Bit: true); + entry.JavaNameHash64 = TypeMapHelper.HashJavaName (entry.JavaName, is64Bit: true); hashes64.Add (entry.JavaNameHash64); } } diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index 558fa42d9d1..13490ca2166 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -8,7 +8,7 @@ #include "shared/xxhash.hh" -static constexpr uint64_t FORMAT_TAG = 0x00035E6972616D58; // 'Xmari^XY' where XY is the format version +static constexpr uint64_t FORMAT_TAG = 0x00045E6972616D58; // 'Xmari^XY' where XY is the format version static constexpr uint32_t COMPRESSED_DATA_MAGIC = 0x5A4C4158; // 'XALZ', little-endian static constexpr uint32_t ASSEMBLY_STORE_MAGIC = 0x41424158; // 'XABA', little-endian @@ -74,8 +74,8 @@ struct TypeMap #else struct TypeMapModuleEntry { - uint32_t type_token_id; - uint32_t java_map_index; + xamarin::android::hash_t managed_type_name_hash; + uint32_t java_map_index; }; struct TypeMapModule @@ -83,19 +83,16 @@ struct TypeMapModule uint8_t module_uuid[16]; uint32_t entry_count; uint32_t duplicate_count; + uint32_t assembly_name_index; TypeMapModuleEntry const *map; TypeMapModuleEntry const *duplicate_map; - char const *assembly_name; - uint8_t *image; - uint32_t java_name_width; - uint8_t *java_map; }; struct TypeMapJava { - uint32_t module_index; - uint32_t type_token_id; - uint32_t java_name_index; + uint32_t module_index; + uint32_t managed_type_name_index; + uint32_t java_name_index; }; #endif @@ -315,12 +312,13 @@ extern "C" { #if defined (DEBUG) [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs #else - [[gnu::visibility("default")]] extern const uint32_t map_module_count; + [[gnu::visibility("default")]] extern const uint32_t managed_to_java_map_module_count; [[gnu::visibility("default")]] extern const uint32_t java_type_count; [[gnu::visibility("default")]] extern const char* const java_type_names[]; - [[gnu::visibility("default")]] extern TypeMapModule map_modules[]; - [[gnu::visibility("default")]] extern const TypeMapJava map_java[]; - [[gnu::visibility("default")]] extern const xamarin::android::hash_t map_java_hashes[]; + [[gnu::visibility("default")]] extern const char* const managed_assembly_names[]; + [[gnu::visibility("default")]] extern TypeMapModule managed_to_java_map[]; + [[gnu::visibility("default")]] extern const TypeMapJava java_to_managed_map[]; + [[gnu::visibility("default")]] extern const xamarin::android::hash_t java_to_managed_hashes[]; #endif [[gnu::visibility("default")]] extern CompressedAssemblies compressed_assemblies; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 0e355298d40..1fd4631373d 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -22,13 +22,13 @@ const TypeMap type_map = { managed_to_java }; #else -const uint32_t map_module_count = 0; +const uint32_t managed_to_java_map_module_count = 0; const uint32_t java_type_count = 0; const char* const java_type_names[] = {}; - -TypeMapModule map_modules[] = {}; -const TypeMapJava map_java[] = {}; -const xamarin::android::hash_t map_java_hashes[] = {}; +const char* const managed_assembly_names[] = {}; +TypeMapModule managed_to_java_map[] = {}; +const TypeMapJava java_to_managed_map[] = {}; +const xamarin::android::hash_t java_to_managed_hashes[] = {}; #endif CompressedAssemblies compressed_assemblies = { From 3abcc6d3f7d2638b9cfa34e17d585e20b1320b0f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 13 Feb 2025 20:41:39 +0100 Subject: [PATCH 104/143] More CoreCLR typemap work --- ...appingReleaseNativeAssemblyGeneratorCLR.cs | 138 +++++++++++++----- src/native/clr/include/xamarin-app.hh | 1 + .../xamarin-app-stub/application_dso_stub.cc | 1 + 3 files changed, 106 insertions(+), 34 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs index 420a7bf31c4..9c43c8e660e 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs @@ -58,19 +58,61 @@ public override ulong GetBufferSize (object data, string fieldName) } } + sealed class TypeMapJavaContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var java_map_entry = EnsureType (data); + + if (String.Compare ("managed_type_name_index", fieldName, StringComparison.Ordinal) == 0) { + return $" managed type name: {java_map_entry.ManagedTypeName}"; + } + + if (String.Compare ("java_name_index", fieldName, StringComparison.Ordinal) == 0) { + return $" Java type name: {java_map_entry.JavaName}"; + } + + return String.Empty; + } + }; + + sealed class TypeMapModuleEntryContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var module_map_entry = EnsureType (data); + + if (String.Compare ("managed_type_name_hash_32", fieldName, StringComparison.Ordinal) == 0 || + String.Compare ("managed_type_name_hash_64", fieldName, StringComparison.Ordinal) == 0) { + return $" managed type name: {module_map_entry.ManagedTypeName}"; + } + + if (String.Compare ("java_map_index", fieldName, StringComparison.Ordinal) == 0) { + return $" Java type name: {module_map_entry.JavaTypeMapEntry.JavaName}"; + } + + return String.Empty; + } + }; + // Order of fields and their type must correspond *exactly* to that in // src/native/clr/include/xamarin-app.hh TypeMapModuleEntry structure + [NativeAssemblerStructContextDataProvider (typeof (TypeMapModuleEntryContextDataProvider))] sealed class TypeMapModuleEntry { [NativeAssembler (Ignore = true)] public TypeMapJava JavaTypeMapEntry; - [NativeAssembler (ValidTarget = NativeAssemblerValidTarget.ThirtyTwoBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + [NativeAssembler (Ignore = true)] + public string ManagedTypeName; + + [NativeAssembler (UsesDataProvider = true, ValidTarget = NativeAssemblerValidTarget.ThirtyTwoBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] public uint managed_type_name_hash_32; - [NativeAssembler (ValidTarget = NativeAssemblerValidTarget.SixtyFourBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + [NativeAssembler (UsesDataProvider = true, ValidTarget = NativeAssemblerValidTarget.SixtyFourBit, MemberName = "managed_type_name_hash", NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] public ulong managed_type_name_hash_64; + [NativeAssembler (UsesDataProvider = true)] public uint java_map_index; } @@ -111,25 +153,27 @@ sealed class TypeMapModule // Order of fields and their type must correspond *exactly* to that in // src/native/clr/include/xamarin-app.hh TypeMapJava structure + [NativeAssemblerStructContextDataProvider (typeof (TypeMapJavaContextDataProvider))] sealed class TypeMapJava { [NativeAssembler (Ignore = true)] public string JavaName; [NativeAssembler (Ignore = true)] - public uint JavaNameHash32; - - [NativeAssembler (Ignore = true)] - public ulong JavaNameHash64; + public string ManagedTypeName; [NativeAssembler (Ignore = true)] - public uint ManagedNameHash32; + public uint JavaNameHash32; [NativeAssembler (Ignore = true)] - public ulong ManagedNameHash64; + public ulong JavaNameHash64; public uint module_index; + + [NativeAssembler (UsesDataProvider = true)] public uint managed_type_name_index; + + [NativeAssembler (UsesDataProvider = true)] public uint java_name_index; } @@ -166,6 +210,7 @@ sealed class ConstructionState public List> MapModules; public Dictionary JavaTypesByName; public List JavaNames; + public List ManagedTypeNames; public List> JavaMap; public List AllModulesData; public List AssemblyNames; @@ -226,7 +271,7 @@ protected override void Construct (LlvmIrModule module) foreach (ModuleMapData mmd in cs.AllModulesData) { var mmdVar = new LlvmIrGlobalVariable (mmd.Entries, mmd.SymbolLabel, LlvmIrVariableOptions.LocalConstant) { - BeforeWriteCallback = UpdateJavaIndexes, + BeforeWriteCallback = SortEntriesAndUpdateJavaIndexes, BeforeWriteCallbackCallerState = cs, }; module.Add (mmdVar); @@ -234,16 +279,27 @@ protected override void Construct (LlvmIrModule module) module.AddGlobalVariable ("java_to_managed_map", cs.JavaMap, LlvmIrVariableOptions.GlobalConstant, " Java to managed map"); module.AddGlobalVariable ("java_type_names", cs.JavaNames, LlvmIrVariableOptions.GlobalConstant, " Java type names"); + module.AddGlobalVariable ("managed_type_names", cs.ManagedTypeNames, LlvmIrVariableOptions.GlobalConstant, " Managed type names"); module.AddGlobalVariable ("managed_assembly_names", cs.AssemblyNames, LlvmIrVariableOptions.GlobalConstant, " Managed assembly names"); } - void UpdateJavaIndexes (LlvmIrVariable variable, LlvmIrModuleTarget target, object? callerState) + void SortEntriesAndUpdateJavaIndexes (LlvmIrVariable variable, LlvmIrModuleTarget target, object? callerState) { ConstructionState cs = EnsureConstructionState (callerState); LlvmIrGlobalVariable gv = EnsureGlobalVariable (variable); IComparer> hashComparer = target.Is64Bit ? javaNameHash64Comparer : javaNameHash32Comparer; var entries = (List>)variable.Value; + if (target.Is64Bit) { + entries.Sort ( + (StructureInstance a, StructureInstance b) => a.Instance.managed_type_name_hash_64.CompareTo (b.Instance.managed_type_name_hash_64) + ); + } else { + entries.Sort ( + (StructureInstance a, StructureInstance b) => a.Instance.managed_type_name_hash_32.CompareTo (b.Instance.managed_type_name_hash_32) + ); + } + foreach (StructureInstance entry in entries) { entry.Instance.java_map_index = GetJavaEntryIndex (entry.Instance.JavaTypeMapEntry); } @@ -309,16 +365,33 @@ ConstructionState EnsureConstructionState (object? callerState) return cs; } + uint GetEntryIndex (string entryValue, Dictionary seenCache, List entryList) + { + if (!seenCache.TryGetValue (entryValue, out uint assemblyNameIndex)) { + entryList.Add (entryValue); + assemblyNameIndex = (uint)(entryList.Count - 1); + seenCache.Add (entryValue, assemblyNameIndex); + } + + return assemblyNameIndex; + } + void InitJavaMap (ConstructionState cs) { + var seenManagedTypeNames = new Dictionary (StringComparer.Ordinal); cs.JavaMap = new List> (); + cs.ManagedTypeNames = new List (); + TypeMapJava map_entry; foreach (TypeMapGenerator.TypeMapReleaseEntry entry in mappingData.JavaTypes) { + uint managedTypeNameIndex = GetEntryIndex (entry.ManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); cs.JavaNames.Add (entry.JavaName); map_entry = new TypeMapJava { + ManagedTypeName = cs.ManagedTypeNames[(int)managedTypeNameIndex], + module_index = (uint)entry.ModuleIndex, // UInt32.MaxValue, -// type_token_id = entry.SkipInJavaToManaged ? 0 : entry.Token, + managed_type_name_index = managedTypeNameIndex, java_name_index = (uint)(cs.JavaNames.Count - 1), JavaName = entry.JavaName, }; @@ -331,16 +404,11 @@ void InitJavaMap (ConstructionState cs) void InitMapModules (ConstructionState cs) { var seenAssemblyNames = new Dictionary (StringComparer.OrdinalIgnoreCase); - var assemblyNames = new List (); cs.MapModules = new List> (); + cs.AssemblyNames = new List (); foreach (TypeMapGenerator.ModuleReleaseData data in mappingData.Modules) { - if (!seenAssemblyNames.TryGetValue (data.AssemblyName, out uint assemblyNameIndex)) { - assemblyNames.Add (data.AssemblyName); - assemblyNameIndex = (uint)(assemblyNames.Count - 1); - seenAssemblyNames.Add (data.AssemblyName, assemblyNameIndex); - } - + uint assemblyNameIndex = GetEntryIndex (data.AssemblyName, seenAssemblyNames, cs.AssemblyNames); string mapName = $"module{moduleCounter++}_managed_to_java"; string duplicateMapName; @@ -355,7 +423,7 @@ void InitMapModules (ConstructionState cs) MapSymbolName = mapName, DuplicateMapSymbolName = duplicateMapName.Length == 0 ? null : duplicateMapName, Data = data, - AssemblyName = assemblyNames[(int)assemblyNameIndex], + AssemblyName = cs.AssemblyNames[(int)assemblyNameIndex], module_uuid = data.MvidBytes, entry_count = (uint)data.Types.Length, @@ -365,7 +433,6 @@ void InitMapModules (ConstructionState cs) cs.MapModules.Add (new StructureInstance (typeMapModuleStructureInfo, map_module)); } - cs.AssemblyNames = assemblyNames; } void MapStructures (LlvmIrModule module) @@ -378,20 +445,23 @@ void MapStructures (LlvmIrModule module) void PrepareMapModuleData (string moduleDataSymbolLabel, IEnumerable moduleEntries, ConstructionState cs) { var mapModuleEntries = new List> (); - // foreach (TypeMapGenerator.TypeMapReleaseEntry entry in moduleEntries) { - // if (!cs.JavaTypesByName.TryGetValue (entry.JavaName, out TypeMapJava javaType)) { - // throw new InvalidOperationException ($"Internal error: Java type '{entry.JavaName}' not found in cache"); - // } - - // var map_entry = new TypeMapModuleEntry { - // JavaTypeMapEntry = javaType, - // type_token_id = entry.Token, - // java_map_index = UInt32.MaxValue, // will be set later, when the target is known - // }; - // mapModuleEntries.Add (new StructureInstance (typeMapModuleEntryStructureInfo, map_entry)); - // } - - // mapModuleEntries.Sort ((StructureInstance a, StructureInstance b) => a.Instance.type_token_id.CompareTo (b.Instance.type_token_id)); + foreach (TypeMapGenerator.TypeMapReleaseEntry entry in moduleEntries) { + if (!cs.JavaTypesByName.TryGetValue (entry.JavaName, out TypeMapJava javaType)) { + throw new InvalidOperationException ($"Internal error: Java type '{entry.JavaName}' not found in cache"); + } + + var map_entry = new TypeMapModuleEntry { + JavaTypeMapEntry = javaType, + ManagedTypeName = entry.ManagedTypeName, + + managed_type_name_hash_32 = (uint)MonoAndroidHelper.GetXxHash (entry.ManagedTypeName, is64Bit: false), + managed_type_name_hash_64 = MonoAndroidHelper.GetXxHash (entry.ManagedTypeName, is64Bit: true), + java_map_index = UInt32.MaxValue, // will be set later, when the target is known + }; + mapModuleEntries.Add (new StructureInstance (typeMapModuleEntryStructureInfo, map_entry)); + } + +// mapModuleEntries.Sort ((StructureInstance a, StructureInstance b) => a.Instance.type_token_id.CompareTo (b.Instance.type_token_id)); cs.AllModulesData.Add (new ModuleMapData (moduleDataSymbolLabel, mapModuleEntries)); } diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index 13490ca2166..d330071c32b 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -315,6 +315,7 @@ extern "C" { [[gnu::visibility("default")]] extern const uint32_t managed_to_java_map_module_count; [[gnu::visibility("default")]] extern const uint32_t java_type_count; [[gnu::visibility("default")]] extern const char* const java_type_names[]; + [[gnu::visibility("default")]] extern const char* const managed_type_names[]; [[gnu::visibility("default")]] extern const char* const managed_assembly_names[]; [[gnu::visibility("default")]] extern TypeMapModule managed_to_java_map[]; [[gnu::visibility("default")]] extern const TypeMapJava java_to_managed_map[]; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 1fd4631373d..38bad32f5e5 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -25,6 +25,7 @@ const TypeMap type_map = { const uint32_t managed_to_java_map_module_count = 0; const uint32_t java_type_count = 0; const char* const java_type_names[] = {}; +const char* const managed_type_names[] = {}; const char* const managed_assembly_names[] = {}; TypeMapModule managed_to_java_map[] = {}; const TypeMapJava java_to_managed_map[] = {}; From 5574c3157138dffa7d28a26d6af1629ee206ebd5 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 14 Feb 2025 16:08:52 +0100 Subject: [PATCH 105/143] Share more code between MonoVM and CoreCLR hosts --- src/native/CMakeLists.txt | 9 + .../clr/host/generate-pinvoke-tables.cc | 2 +- src/native/clr/include/constants.hh | 2 +- src/native/clr/include/host/host.hh | 2 +- .../clr/include/host/pinvoke-override.hh | 2 +- .../include/runtime-base/android-system.hh | 4 +- .../clr/include/runtime-base/jni-wrappers.hh | 209 ---- src/native/clr/include/runtime-base/logger.hh | 2 +- .../clr/include/runtime-base/monodroid-dl.hh | 4 +- src/native/clr/include/runtime-base/search.hh | 60 -- .../clr/include/runtime-base/strings.hh | 957 ----------------- .../include/runtime-base/timing-internal.hh | 2 +- src/native/clr/include/runtime-base/util.hh | 6 +- src/native/clr/include/shared/cpp-util.hh | 271 ----- src/native/clr/include/shared/helpers.hh | 105 -- src/native/clr/include/shared/log_level.hh | 112 -- src/native/clr/include/shared/log_types.hh | 2 +- src/native/clr/include/shared/xxhash.hh | 194 ---- src/native/clr/include/xamarin-app.hh | 2 +- src/native/common/include/shared/helpers.hh | 1 - .../mono/monodroid/embedded-assemblies-zip.cc | 2 +- .../mono/monodroid/embedded-assemblies.hh | 4 +- .../mono/monodroid/monodroid-glue-internal.hh | 1 + src/native/mono/monodroid/monodroid-glue.cc | 10 +- src/native/mono/runtime-base/jni-wrappers.hh | 209 ---- src/native/mono/runtime-base/logger.cc | 4 +- src/native/mono/runtime-base/search.hh | 60 -- src/native/mono/runtime-base/strings.hh | 964 ------------------ src/native/mono/runtime-base/util.hh | 2 +- src/native/mono/shared/helpers.cc | 2 +- src/native/mono/shared/helpers.hh | 106 -- src/native/mono/shared/log_functions.cc | 2 +- src/native/mono/shared/log_level.hh | 26 - src/native/mono/shared/log_types.hh | 2 +- src/native/mono/shared/xxhash.hh | 194 ---- .../debug-app-helper.cc | 2 +- 36 files changed, 40 insertions(+), 3498 deletions(-) delete mode 100644 src/native/clr/include/runtime-base/jni-wrappers.hh delete mode 100644 src/native/clr/include/runtime-base/search.hh delete mode 100644 src/native/clr/include/runtime-base/strings.hh delete mode 100644 src/native/clr/include/shared/cpp-util.hh delete mode 100644 src/native/clr/include/shared/helpers.hh delete mode 100644 src/native/clr/include/shared/log_level.hh delete mode 100644 src/native/clr/include/shared/xxhash.hh delete mode 100644 src/native/mono/runtime-base/jni-wrappers.hh delete mode 100644 src/native/mono/runtime-base/search.hh delete mode 100644 src/native/mono/runtime-base/strings.hh delete mode 100644 src/native/mono/shared/helpers.hh delete mode 100644 src/native/mono/shared/log_level.hh delete mode 100644 src/native/mono/shared/xxhash.hh diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index daabbae428f..02e477f3d68 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -235,6 +235,8 @@ if(IS_CLR_RUNTIME) ${RUNTIME_INCLUDE_DIR} ) endmacro() +else() + include_directories(mono) endif() # @@ -262,6 +264,13 @@ macro(xa_add_compile_definitions TARGET) ${TARGET} PRIVATE TARGET_ANDROID + XA_HOST_CLR + ) + else() + target_compile_definitions( + ${TARGET} + PRIVATE + XA_HOST_MONOVM ) endif() endmacro() diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index 834574731ab..cd6da7be976 100644 --- a/src/native/clr/host/generate-pinvoke-tables.cc +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -26,7 +26,7 @@ #include #include -#include "xxhash.hh" +#include namespace fs = std::filesystem; using namespace xamarin::android; diff --git a/src/native/clr/include/constants.hh b/src/native/clr/include/constants.hh index a0d1b42630d..5cb344e3cf4 100644 --- a/src/native/clr/include/constants.hh +++ b/src/native/clr/include/constants.hh @@ -5,7 +5,7 @@ #include -#include "shared/cpp-util.hh" +#include namespace xamarin::android { class Constants diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 7c47bb8a337..9d66d8b720a 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -5,7 +5,7 @@ #include #include -#include "../runtime-base/jni-wrappers.hh" +#include #include "../runtime-base/timing.hh" #include "../shared/log_types.hh" #include "managed-interface.hh" diff --git a/src/native/clr/include/host/pinvoke-override.hh b/src/native/clr/include/host/pinvoke-override.hh index 73c94086194..e1b7afebd95 100644 --- a/src/native/clr/include/host/pinvoke-override.hh +++ b/src/native/clr/include/host/pinvoke-override.hh @@ -28,7 +28,7 @@ #endif #include "../runtime-base/monodroid-dl.hh" -#include "../shared/xxhash.hh" +#include namespace xamarin::android { struct PinvokeEntry diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index ae92a1977da..24324da2353 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -9,8 +9,8 @@ #include "../constants.hh" #include "../shared/log_types.hh" #include "../runtime-base/cpu-arch.hh" -#include "jni-wrappers.hh" -#include "strings.hh" +#include +#include #include "util.hh" struct BundledProperty; diff --git a/src/native/clr/include/runtime-base/jni-wrappers.hh b/src/native/clr/include/runtime-base/jni-wrappers.hh deleted file mode 100644 index 679aed3df59..00000000000 --- a/src/native/clr/include/runtime-base/jni-wrappers.hh +++ /dev/null @@ -1,209 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace xamarin::android -{ - class jstring_array_wrapper; - - class jstring_wrapper - { - public: - explicit jstring_wrapper (JNIEnv *_env) noexcept - : env (_env), - jstr (nullptr) - { - abort_if_invalid_pointer_argument (_env, "_env"); - } - - explicit jstring_wrapper (JNIEnv *_env, const jobject jo) noexcept - : env (_env), - jstr (reinterpret_cast (jo)) - { - abort_if_invalid_pointer_argument (_env, "_env"); - } - - explicit jstring_wrapper (JNIEnv *_env, const jstring js) noexcept - : env (_env), - jstr (js) - { - abort_if_invalid_pointer_argument (_env, "_env"); - } - - jstring_wrapper (const jstring_wrapper&) = delete; - - ~jstring_wrapper () noexcept - { - release (); - } - - jstring_wrapper& operator=(const jstring_wrapper&) = delete; - - bool hasValue () noexcept - { - return jstr != nullptr; - } - - private: - [[gnu::always_inline]] - void ensure_cstr () noexcept - { - if (cstr != nullptr || env == nullptr) { - return; - } - - cstr = env->GetStringUTFChars (jstr, nullptr); - } - - public: - const char* get_cstr () noexcept - { - if (jstr == nullptr) { - return nullptr; - } - - ensure_cstr (); - return cstr; - } - - [[gnu::always_inline]] - const std::string_view get_string_view () noexcept - { - if (jstr == nullptr) { - return {}; - } - - ensure_cstr (); - return {cstr}; - } - - jstring_wrapper& operator= (const jobject new_jo) noexcept - { - assign (reinterpret_cast (new_jo)); - return *this; - } - - jstring_wrapper& operator= (const jstring new_js) noexcept - { - assign (new_js); - return *this; - } - - protected: - void release () noexcept - { - if (jstr == nullptr || cstr == nullptr || env == nullptr) { - return; - } - env->ReleaseStringUTFChars (jstr, cstr); - jobjectRefType type = env->GetObjectRefType (jstr); - switch (type) { - case JNILocalRefType: - env->DeleteLocalRef (jstr); - break; - - case JNIGlobalRefType: - env->DeleteGlobalRef (jstr); - break; - - case JNIWeakGlobalRefType: - env->DeleteWeakGlobalRef (jstr); - break; - - case JNIInvalidRefType: // To hush compiler warning - break; - } - - jstr = nullptr; - cstr = nullptr; - } - - void assign (const jstring new_js) noexcept - { - release (); - if (new_js == nullptr) { - return; - } - - jstr = new_js; - cstr = nullptr; - } - - friend class jstring_array_wrapper; - - private: - jstring_wrapper () - : env (nullptr), - jstr (nullptr) - {} - - private: - JNIEnv *env; - jstring jstr; - const char *cstr = nullptr; - }; - - class jstring_array_wrapper - { - public: - explicit jstring_array_wrapper (JNIEnv *_env) noexcept - : jstring_array_wrapper(_env, nullptr) - {} - - explicit jstring_array_wrapper (JNIEnv *_env, jobjectArray _arr) - : env (_env), - arr (_arr) - { - abort_if_invalid_pointer_argument (_env, "_env"); - if (_arr != nullptr) { - len = static_cast(_env->GetArrayLength (_arr)); - if (len > sizeof (static_wrappers) / sizeof (jstring_wrapper)) { - wrappers = new jstring_wrapper [len]; - } else { - wrappers = static_wrappers; - } - } else { - len = 0; - wrappers = nullptr; - } - } - - ~jstring_array_wrapper () noexcept - { - if (wrappers != nullptr && wrappers != static_wrappers) { - delete[] wrappers; - } - } - - size_t get_length () const noexcept - { - return len; - } - - jstring_wrapper& operator[] (size_t index) noexcept - { - if (index >= len) { - return invalid_wrapper; - } - - if (wrappers [index].env == nullptr) { - wrappers [index].env = env; - wrappers [index].jstr = reinterpret_cast (env->GetObjectArrayElement (arr, static_cast(index))); - } - - return wrappers [index]; - } - - private: - JNIEnv *env; - jobjectArray arr; - size_t len; - jstring_wrapper *wrappers; - jstring_wrapper static_wrappers[5]; - jstring_wrapper invalid_wrapper; - }; -} diff --git a/src/native/clr/include/runtime-base/logger.hh b/src/native/clr/include/runtime-base/logger.hh index 45c9e2449bd..f9285456bc6 100644 --- a/src/native/clr/include/runtime-base/logger.hh +++ b/src/native/clr/include/runtime-base/logger.hh @@ -5,7 +5,7 @@ #include #include -#include "strings.hh" +#include namespace xamarin::android { class Logger diff --git a/src/native/clr/include/runtime-base/monodroid-dl.hh b/src/native/clr/include/runtime-base/monodroid-dl.hh index d52e4d6f13a..c35a89052a4 100644 --- a/src/native/clr/include/runtime-base/monodroid-dl.hh +++ b/src/native/clr/include/runtime-base/monodroid-dl.hh @@ -7,11 +7,11 @@ #include -#include "../shared/xxhash.hh" +#include #include "../xamarin-app.hh" #include "android-system.hh" -#include "search.hh" +#include #include "startup-aware-lock.hh" namespace xamarin::android diff --git a/src/native/clr/include/runtime-base/search.hh b/src/native/clr/include/runtime-base/search.hh deleted file mode 100644 index 8153759f841..00000000000 --- a/src/native/clr/include/runtime-base/search.hh +++ /dev/null @@ -1,60 +0,0 @@ -// Dear Emacs, this is a -*- C++ -*- header -#pragma once - -#include - -#include "../shared/xxhash.hh" - -namespace xamarin::android { - class Search final - { - public: - template - [[gnu::always_inline]] - static ssize_t binary_search (hash_t key, const T *arr, size_t n) noexcept - { - static_assert (equal != nullptr, "equal is a required template parameter"); - static_assert (less_than != nullptr, "less_than is a required template parameter"); - - ssize_t left = -1z; - ssize_t right = static_cast(n); - - while (right - left > 1) { - ssize_t middle = (left + right) >> 1u; - if (less_than (arr[middle], key)) { - left = middle; - } else { - right = middle; - } - } - - return equal (arr[right], key) ? right : -1z; - } - - [[gnu::always_inline]] - static ssize_t binary_search (hash_t key, const hash_t *arr, size_t n) noexcept - { - auto equal = [](hash_t const& entry, hash_t key) -> bool { return entry == key; }; - auto less_than = [](hash_t const& entry, hash_t key) -> bool { return entry < key; }; - - return binary_search (key, arr, n); - } - - [[gnu::always_inline]] - static ptrdiff_t binary_search_branchless (hash_t x, const hash_t *arr, uint32_t len) noexcept - { - const hash_t *base = arr; - while (len > 1) { - uint32_t half = len >> 1; - // __builtin_prefetch(&base[(len - half) / 2]); - // __builtin_prefetch(&base[half + (len - half) / 2]); - base = (base[half] < x ? &base[half] : base); - len -= half; - } - - //return *(base + (*base < x)); - ptrdiff_t ret = (base + (*base < x)) - arr; - return arr[ret] == x ? ret : -1; - } - }; -} diff --git a/src/native/clr/include/runtime-base/strings.hh b/src/native/clr/include/runtime-base/strings.hh deleted file mode 100644 index dc2933f4259..00000000000 --- a/src/native/clr/include/runtime-base/strings.hh +++ /dev/null @@ -1,957 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../shared/helpers.hh" -#include "../constants.hh" - -namespace xamarin::android { - static constexpr size_t SENSIBLE_TYPE_NAME_LENGTH = 128uz; - static constexpr size_t SENSIBLE_PATH_MAX = 256uz; - -#if DEBUG - static constexpr bool BoundsCheck = true; -#else - static constexpr bool BoundsCheck = false; -#endif - - enum class string_segment_error - { - index_out_of_range, - }; - - static inline auto to_string (string_segment_error error) -> std::string_view const - { - using std::operator""sv; - - switch (error) { - case string_segment_error::index_out_of_range: - return "Index out of range"sv; - - default: - return "Unknown error"sv; - } - } - - class string_segment - { - public: - [[gnu::always_inline]] - auto initialized () const noexcept -> bool - { - return !_fresh; - } - - [[gnu::always_inline]] - auto start () const noexcept -> const char* - { - return _start; - } - - [[gnu::always_inline]] - auto at (size_t offset) const noexcept -> std::expected - { - if (offset >= length ()) { - return std::unexpected (string_segment_error::index_out_of_range); - } - - return _start + offset; - } - - [[gnu::always_inline]] - auto length () const noexcept -> size_t - { - return _length; - } - - [[gnu::always_inline]] - auto empty () const noexcept -> bool - { - return length () == 0; - } - - [[gnu::always_inline]] - auto equal (const char *s) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return equal (s, strlen (s)); - } - - [[gnu::always_inline]] - auto equal (const char *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - if (length () != s_length) { - return false; - } - - if (!can_access (s_length)) [[unlikely]] { - return false; - } - - if (length () == 0) { - return true; - } - - return memcmp (_start, s, length ()) == 0; - } - - template [[gnu::always_inline]] - auto equal (const char (&s)[Size]) noexcept -> bool - { - return equal (s, Size - 1); - } - - [[gnu::always_inline]] - auto equal (std::string_view const& s) noexcept -> bool - { - return equal (s.data (), s.length ()); - } - - [[gnu::always_inline]] - auto starts_with_c (const char *s) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return starts_with (s, strlen (s)); - } - - [[gnu::always_inline]] - auto starts_with (const char *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr || !can_access (s_length)) { - return false; - } - - if (length () < s_length) { - return false; - } - - return memcmp (start (), s, s_length) == 0; - } - - template [[gnu::always_inline]] - auto starts_with (const char (&s)[Size]) const noexcept -> bool - { - return starts_with (s, Size - 1); - } - - [[gnu::always_inline]] - auto starts_with (std::string_view const& s) const noexcept -> bool - { - return starts_with (s.data (), s.length ()); - } - - [[gnu::always_inline]] - auto has_at (const char ch, size_t index) const noexcept -> bool - { - if (!can_access (index)) { - return false; - } - - return start ()[index] == ch; - } - - [[gnu::always_inline]] - auto find (const char ch, size_t start_index) const noexcept -> ssize_t - { - if (!can_access (start_index)) { - return -1; - } - - while (start_index <= length ()) { - if (start ()[start_index] == ch) { - return static_cast(start_index); - } - start_index++; - } - - return -1; - } - - template [[gnu::always_inline]] - auto to_integer (T &val, size_t start_index = 0uz, int base = 10) const noexcept -> bool - { - static_assert (std::is_integral_v); - constexpr T min = std::numeric_limits::min (); - constexpr T max = std::numeric_limits::max (); - using integer = typename std::conditional, int64_t, uint64_t>::type; - - if (length () == 0uz) { - return false; - } - - if (!can_access (start_index)) { - log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); - return false; - } - - // FIXME: this is less than ideal... we shouldn't need another buffer here - size_t slen = length () - start_index; - char s[slen + 1]; - - memcpy (s, start () + start_index, slen); - s[slen] = '\0'; - - integer ret; - char *endp; - bool out_of_range; - errno = 0; - if constexpr (std::is_signed_v) { - ret = strtoll (s, &endp, base); - out_of_range = ret < min || ret > max; - } else { - ret = strtoull (s, &endp, base); - out_of_range = ret > max; - } - - if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); - return false; - } - - if (endp == s) { - log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); - return false; - } - - if (*endp != '\0') { - log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); - return false; - } - - val = static_cast(ret); - return true; - } - - private: - [[gnu::always_inline]] - auto can_access (size_t index) const noexcept -> bool - { - if (!initialized () || start () == nullptr) [[unlikely]] { - return false; - } - - if (index > length ()) { - return false; - } - - return true; - } - - protected: - size_t _last_index = 0uz; - bool _fresh = true; - const char *_start = nullptr; - size_t _length = 0uz; - - template friend class string_base; - }; - - template - class local_storage - { - protected: - using LocalStoreArray = std::array; - - public: - static constexpr bool has_resize = HasResize; - - public: - explicit local_storage (size_t size) noexcept - { - static_assert (MaxStackSize > 0, "MaxStackSize must be more than 0"); - init_store (size < MaxStackSize ? MaxStackSize : size); - } - - virtual ~local_storage () - { - free_store (); - } - - auto get () noexcept -> T* - { - return allocated_store == nullptr ? local_store.data () : allocated_store; - } - - auto get () const noexcept -> const T* - { - return allocated_store == nullptr ? local_store.data () : allocated_store; - } - - auto size () const noexcept -> size_t - { - return store_size; - } - - protected: - [[gnu::always_inline]] - void init_store (size_t new_size) noexcept - { - if (new_size > MaxStackSize) { - allocated_store = new T[new_size]; - } else { - allocated_store = nullptr; - } - store_size = new_size; - } - - [[gnu::always_inline]] - void free_store () noexcept - { - if (allocated_store == nullptr) { - return; - } - - delete[] allocated_store; - } - - [[gnu::always_inline]] - auto get_local_store () noexcept -> LocalStoreArray& - { - return local_store; - } - - [[gnu::always_inline]] - auto get_allocated_store () noexcept -> T* - { - return allocated_store; - } - - private: - size_t store_size; - LocalStoreArray local_store; - T* allocated_store; - }; - - // This class is meant to provide a *very* thin veneer (by design) over space allocated for *local* buffers - that - // is one which are not meant to survive the exit of the function they are created in. The idea is that the caller - // knows the size of the buffer they need and they want to put the buffer on stack, if it doesn't exceed a certain - // value, or dynamically allocate memory if more is needed. Even though the class could be used on its own, it's - // really meant to be a base for more specialized buffers. There are not many safeguards, by design - the code is - // meant to be performant. This is the reason why the size is static throughout the life of the object, so that we - // can perform as few checks as possible. - - template using static_local_storage_base = local_storage; - - template - class static_local_storage final : public static_local_storage_base - { - using base = static_local_storage_base; - - public: - explicit static_local_storage (size_t initial_size) noexcept - : base (initial_size) - {} - }; - - template using dynamic_local_storage_base = local_storage; - - template - class dynamic_local_storage final : public dynamic_local_storage_base - { - using base = dynamic_local_storage_base; - - public: - explicit dynamic_local_storage (size_t initial_size = 0uz) noexcept - : base (initial_size) - {} - - // - // If `new_size` is smaller than the current size and the dynamic store is allocated, data WILL NOT be - // preserved. - // - // If `new_size` is bigger than the current size bigger than MaxStackSize, data will be copied to the new - // dynamically allocated store - // - // If `new_size` is smaller or equal to `MaxStackSize`, no changes are made unless dynamic store was allocated, - // in which case it will be freed - // - void resize (size_t new_size) noexcept - { - size_t old_size = base::size (); - - if (new_size == old_size) { - return; - } - - if (new_size <= MaxStackSize) { - new_size = MaxStackSize; - base::free_store (); - return; - } - - if (new_size < old_size) { - base::free_store (); - base::init_store (new_size); - return; - } - - T* old_allocated_store = base::get_allocated_store (); - base::init_store (new_size); - - T* new_allocated_store = base::get_allocated_store (); - if (old_allocated_store != nullptr) { - std::memcpy (new_allocated_store, old_allocated_store, old_size); - delete[] old_allocated_store; - return; - } - - std::memcpy (new_allocated_store, base::get_local_store ().data (), MaxStackSize); - } - }; - - template - class string_base - { - protected: - static constexpr TChar NUL = '\0'; - static constexpr TChar ZERO = '0'; - - public: - explicit string_base (size_t initial_size = 0uz) - : buffer (initial_size) - { - // Currently we care only about `char`, maybe in the future we'll add support for `wchar` (if needed) - static_assert (std::is_same_v, "TChar must be an 8-bit character type"); - - clear (); - } - - explicit string_base (const string_segment &token) - : string_base (token.initialized () ? token.length () : 0) - { - if (token.initialized ()) { - assign (token.start (), token.length ()); - } - } - - [[gnu::always_inline]] - auto length () const noexcept -> size_t - { - return idx; - } - - [[gnu::always_inline]] - auto empty () const noexcept -> bool - { - return length () == 0; - } - - [[gnu::always_inline]] - void set_length (size_t new_length) noexcept - { - if (new_length >= buffer.size ()) { - return; - } - - idx = new_length; - terminate (); - } - - [[gnu::always_inline]] - void clear () noexcept - { - set_length (0); - buffer.get ()[0] = NUL; - } - - [[gnu::always_inline]] - void terminate () noexcept - { - buffer.get ()[idx] = NUL; - } - - [[gnu::always_inline]] - auto replace (const TChar c1, const TChar c2) noexcept -> string_base& - { - if (empty ()) { - return *this; - } - - for (size_t i = 0uz; i < length (); i++) { - if (buffer.get ()[i] == c1) { - buffer.get ()[i] = c2; - } - } - - return *this; - } - - [[gnu::always_inline]] - auto append (const TChar* s, size_t length) noexcept -> string_base& - { - if (s == nullptr || length == 0uz) { - return *this; - } - - resize_for_extra (length); - if constexpr (BoundsCheck) { - ensure_have_extra (length); - } - - std::memcpy (buffer.get () + idx, s, length); - idx += length; - buffer.get ()[idx] = NUL; - - return *this; - } - - template - [[gnu::always_inline]] - auto append (string_base const& str) noexcept -> string_base& - { - return append (str.get (), str.length ()); - } - - [[gnu::always_inline]] - auto append (std::string_view const& sv) noexcept -> string_base& - { - return append (sv.data (), sv.length ()); - } - - template [[gnu::always_inline]] - auto append (const char (&s)[Size]) noexcept -> string_base& - { - return append (s, Size - 1); - } - - [[gnu::always_inline]] - auto append_c (const char *s) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - return append (s, strlen (s)); - } - - [[gnu::always_inline]] - auto append (int16_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (buffer.get (), i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint16_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (int32_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint32_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (int64_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint64_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto assign (const TChar* s, size_t length) noexcept -> string_base& - { - idx = 0; - return append (s, length); - } - - [[gnu::always_inline]] - auto assign_c (const TChar* s) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - return assign (s, strlen (s)); - } - - [[gnu::always_inline]] - auto assign (std::string_view const& sv) noexcept -> string_base& - { - return assign (sv.data (), sv.size ()); - } - - [[gnu::always_inline]] - auto assign (std::string const& s) noexcept -> string_base& - { - return assign (s.data (), s.size ()); - } - - template [[gnu::always_inline]] - auto assign (const char (&s)[Size]) noexcept -> string_base& - { - return assign (s, Size - 1); - } - - template - [[gnu::always_inline]] - auto assign (string_base const& str) noexcept -> string_base& - { - return assign (str.get (), str.length ()); - } - - [[gnu::always_inline]] - auto assign (const TChar* s, size_t offset, size_t count) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - if constexpr (BoundsCheck) { - size_t slen = strlen (s); - if (offset + count > slen) { - Helpers::abort_application ("Attempt to assign data from a string exceeds the source string length"); - } - } - - return assign (s + offset, count); - } - - [[gnu::always_inline]] - auto next_token (size_t start_index, const TChar separator, string_segment& token) const noexcept -> bool - { - size_t index; - if (token._fresh) { - token._fresh = false; - token._last_index = start_index; - index = start_index; - } else { - index = token._last_index + 1; - } - - token._start = nullptr; - token._length = 0; - if (token._last_index + 1 >= buffer.size ()) { - return false; - } - - const TChar *start = buffer.get () + index; - const TChar *p = start; - while (*p != NUL) { - if (*p == separator) { - break; - } - p++; - index++; - } - - token._last_index = *p == NUL ? buffer.size () : index; - token._start = start; - token._length = static_cast(p - start); - - return true; - } - - [[gnu::always_inline]] - auto next_token (const char separator, string_segment& token) const noexcept -> bool - { - return next_token (0, separator, token); - } - - [[gnu::always_inline]] - auto index_of (const TChar ch) const noexcept -> ssize_t - { - const TChar *p = buffer.get (); - while (p != nullptr && *p != NUL) { - if (*p == ch) { - return static_cast(p - buffer.get ()); - } - p++; - } - - return -1; - } - - [[gnu::always_inline]] - auto starts_with (const TChar *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr || s_length == 0 || s_length > buffer.size ()) { - return false; - } - - return memcmp (buffer.get (), s, s_length) == 0; - } - - [[gnu::always_inline]] - auto starts_with_c (const char* s) noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return starts_with (s, strlen (s)); - } - - template [[gnu::always_inline]] - auto starts_with (const char (&s)[Size]) noexcept -> bool - { - return starts_with (s, Size - 1); - } - - [[gnu::always_inline]] - auto starts_with (std::string_view const& s) noexcept -> bool - { - return starts_with (s.data (), s.length ()); - } - - [[gnu::always_inline]] - void set_length_after_direct_write (size_t new_length) noexcept - { - set_length (new_length); - terminate (); - } - - [[gnu::always_inline]] - void set_at (size_t index, const TChar ch) noexcept - { - ensure_valid_index (index); - TChar *p = buffer + index; - if (*p == NUL) { - return; - } - - *p = ch; - } - - [[gnu::always_inline]] - auto get_at (size_t index) const noexcept -> const TChar - { - ensure_valid_index (index); - return *(buffer.get () + index); - } - - [[gnu::always_inline]] - auto get_at (size_t index) noexcept -> TChar& - { - ensure_valid_index (index); - return *(buffer.get () + index); - } - - [[gnu::always_inline]] - auto get () const noexcept -> const TChar* - { - return buffer.get (); - } - - [[gnu::always_inline]] - auto get () noexcept -> TChar* - { - return buffer.get (); - } - - [[gnu::always_inline]] - auto size () const noexcept -> size_t - { - return buffer.size (); - } - - [[gnu::always_inline]] - auto operator[] (size_t index) const noexcept -> char - { - return get_at (index); - } - - [[gnu::always_inline]] - auto operator[] (size_t index) noexcept -> char& - { - return get_at (index); - } - - protected: - template [[gnu::always_inline]] - void append_integer (Integer i) noexcept - { - static_assert (std::is_integral_v); - - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - if constexpr (BoundsCheck) { - ensure_have_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - } - - if (i == 0) { - constexpr char zero[] = "0"; - constexpr size_t zero_len = sizeof(zero) - 1uz; - - append (zero, zero_len); - return; - } - - TChar temp_buf[Constants::MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz]; - TChar *p = temp_buf + Constants::MAX_INTEGER_DIGIT_COUNT_BASE10; - *p = NUL; - TChar *end = p; - - uint32_t x; - if constexpr (sizeof(Integer) > 4uz) { - uint64_t y; - - if constexpr (std::is_signed_v) { - y = static_cast(i > 0 ? i : -i); - } else { - y = static_cast(i); - } - while (y > std::numeric_limits::max ()) { - *--p = (y % 10) + ZERO; - y /= 10; - } - x = static_cast(y); - } else { - if constexpr (std::is_signed_v) { - x = static_cast(i > 0 ? i : -i); - } else { - x = static_cast(i); - } - } - - while (x > 0) { - *--p = (x % 10) + ZERO; - x /= 10; - } - - if constexpr (std::is_signed_v) { - if (i < 0) - *--p = '-'; - } - - append (p, static_cast(end - p)); - } - - [[gnu::always_inline]] - void ensure_valid_index (size_t access_index) const noexcept - { - if (access_index < idx && access_index < buffer.size ()) [[likely]] { - return; - } - - char *message = nullptr; - int n = asprintf (&message, "Index %zu is out of range (0 - %zu)", access_index, idx); - Helpers::abort_application (n == -1 ? "Index out of range" : message); - } - - [[gnu::always_inline]] - void ensure_have_extra (size_t length) noexcept - { - size_t needed_space = Helpers::add_with_overflow_check (length, idx + 1); - if (needed_space > buffer.size ()) { - char *message = nullptr; - int n = asprintf ( - &message, - "Attempt to store too much data in a buffer (capacity: %zu; exceeded by: %zu)", - buffer.size (), - needed_space - buffer.size () - ); - Helpers::abort_application (n == -1 ? "Attempt to store too much data in a buffer" : message); - } - } - - [[gnu::always_inline]] - void resize_for_extra (size_t needed_space) noexcept - { - if constexpr (TStorage::has_resize) { - size_t required_space = Helpers::add_with_overflow_check (needed_space, idx + 1uz); - size_t current_size = buffer.size (); - if (required_space > current_size) { - size_t new_size = Helpers::add_with_overflow_check (current_size, (current_size / 2uz)); - new_size = Helpers::add_with_overflow_check (new_size, required_space); - buffer.resize (new_size); - } - } - } - - private: - size_t idx; - TStorage buffer; - }; - - template - class static_local_string : public string_base, TChar> - { - using base = string_base, TChar>; - - public: - explicit static_local_string (size_t initial_size = 0uz) noexcept - : base (initial_size) - {} - - explicit static_local_string (const string_segment &token) noexcept - : base (token) - {} - - template - explicit static_local_string (const char (&str)[N]) - : base (N) - { - append (str); - } - }; - - template - class dynamic_local_string : public string_base, TChar> - { - using base = string_base, TChar>; - - public: - explicit dynamic_local_string (size_t initial_size = 0uz) - : base (initial_size) - {} - - explicit dynamic_local_string (const string_segment &token) noexcept - : base (token) - {} - - template - explicit dynamic_local_string (const char (&str)[N]) - : base (N) - { - base::append (str); - } - - explicit dynamic_local_string (std::string_view const& str) - : base (str.length ()) - { - base::append (str); - } - }; -} diff --git a/src/native/clr/include/runtime-base/timing-internal.hh b/src/native/clr/include/runtime-base/timing-internal.hh index d9c29ca53a9..6897c34df1d 100644 --- a/src/native/clr/include/runtime-base/timing-internal.hh +++ b/src/native/clr/include/runtime-base/timing-internal.hh @@ -10,7 +10,7 @@ #include #include #include "startup-aware-lock.hh" -#include "strings.hh" +#include #include "util.hh" #include "../constants.hh" #include "monodroid-state.hh" diff --git a/src/native/clr/include/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 02b559fcf78..78100e05a71 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -11,11 +11,11 @@ #include #include "../constants.hh" -#include "../shared/helpers.hh" +#include #include "archive-dso-stub-config.hh" -#include "jni-wrappers.hh" +#include #include "logger.hh" -#include "strings.hh" +#include namespace xamarin::android { namespace detail { diff --git a/src/native/clr/include/shared/cpp-util.hh b/src/native/clr/include/shared/cpp-util.hh deleted file mode 100644 index 396292613bb..00000000000 --- a/src/native/clr/include/shared/cpp-util.hh +++ /dev/null @@ -1,271 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "helpers.hh" - -namespace xamarin::android::detail { - [[gnu::always_inline, gnu::flatten]] - static inline const char* - _format_message (const char *format, ...) noexcept - { - va_list ap; - va_start (ap, format); - - char *message; - int ret = vasprintf (&message, format, ap); - - va_end (ap); - return ret == -1 ? "Out of memory" : message; - } - - [[gnu::always_inline]] - static inline std::string get_function_name (const char *signature) - { - using std::operator""sv; - - std::string_view sig { signature }; - if (sig.length () == 0) { - return ""; - } - - auto splitSignature = sig | std::views::split ("::"sv) | std::ranges::to> (); - - std::string ret; - if (splitSignature.size () > 1) { - ret.append (splitSignature [splitSignature.size () - 2]); - ret.append ("::"sv); - } - std::string_view func_name { splitSignature[splitSignature.size () - 1] }; - std::string_view::size_type args_pos = func_name.find ('('); - std::string_view::size_type name_start_pos = func_name.find (' '); - - if (name_start_pos == std::string_view::npos) { - name_start_pos = 0; - } else { - name_start_pos++; // point to after the space which separates return type from name - if (name_start_pos >= func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - } - - if (args_pos == std::string_view::npos) { - ret.append (func_name.substr (name_start_pos)); - } else { - // If there's a snafu with positions, start from 0 - if (name_start_pos >= args_pos || name_start_pos > func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - - ret.append (func_name.substr (name_start_pos, args_pos - name_start_pos)); - } - - return ret; - } -} - -template F> -[[gnu::always_inline, gnu::flatten]] -static inline void -abort_unless (bool condition, F&& get_message, std::source_location sloc = std::source_location::current ()) noexcept -{ - static_assert (std::is_same::type, const char*>::value, "get_message must return 'const char*'"); - - if (condition) [[likely]] { - return; - } - - xamarin::android::Helpers::abort_application (std::invoke (get_message), true /* log_location */, sloc); -} - -[[gnu::always_inline, gnu::flatten]] -static inline void -abort_unless (bool condition, const char *message, std::source_location sloc = std::source_location::current ()) noexcept -{ - if (condition) [[likely]] { - return; - } - xamarin::android::Helpers::abort_application (message, true /* log_location */, sloc); -} - -template -[[gnu::always_inline, gnu::flatten]] -static inline void -abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_location sloc = std::source_location::current ()) noexcept -{ - abort_unless ( - ptr != nullptr, - [&ptr_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a valid pointer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - ptr_name - ); - }, - sloc - ); -} - -[[gnu::always_inline, gnu::flatten]] -static inline void -abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_location sloc = std::source_location::current ()) noexcept -{ - abort_unless ( - arg > 0, - [&arg_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a positive integer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - arg_name - ); - }, - sloc - ); -} - -// Helper to use in "printf debugging". Normally not used in code anywhere. No code should be shipped with any -// of the calls present. -[[gnu::always_inline]] -inline void pd_log_location (std::source_location sloc = std::source_location::current ()) noexcept -{ - log_info_nocheck (LOG_DEFAULT, "loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); -} - -namespace xamarin::android -{ - template - struct CDeleter final - { - using UnderlyingType = std::remove_cv_t; - - void operator() (T* p) - { - UnderlyingType *ptr; - - if constexpr (std::is_const_v) { - ptr = const_cast*> (p); - } else { - ptr = p; - } - - std::free (reinterpret_cast(ptr)); - } - }; - - template - using c_unique_ptr = std::unique_ptr>; - - template - using char_array = std::array; - - template - constexpr auto concat_const (const char (&...parts)[Length]) - { - // `parts` being constant string arrays, Length for each of them includes the trailing NUL byte, thus the - // `sizeof... (Length)` part which subtracts the number of template parameters - the amount of NUL bytes so that - // we don't waste space. - constexpr size_t total_length = (... + Length) - sizeof... (Length); - char_array ret; // lgtm [cpp/paddingbyteinformationdisclosure] the buffer is filled in the loop below - ret[total_length] = 0; - - size_t i = 0uz; - for (char const* from : {parts...}) { - for (; *from != '\0'; i++) { - ret[i] = *from++; - } - } - - return ret; - }; - - template - concept StringViewPart = std::is_same_v; - - template - consteval auto concat_string_views (T const&... parts) - { - std::array ret; // lgtm [cpp/paddingbyteinformationdisclosure] the buffer is filled in the loop below - ret[TotalLength] = 0; - - size_t i = 0; - for (std::string_view const& sv : {parts...}) { - for (const char ch : sv) { - ret[i] = ch; - i++; - } - } - - return ret; - } - - consteval size_t calc_size (std::string_view const& sv1) noexcept - { - return sv1.size (); - } - - template - consteval size_t calc_size (std::string_view const& sv1, T const&... other_svs) noexcept - { - return sv1.size () + calc_size (other_svs...); - } - - template , int> = 0> - constexpr TEnum operator & (TEnum l, TEnum r) noexcept - { - using etype = std::underlying_type_t; - return static_cast(static_cast(l) & static_cast(r)); - } - - template , int> = 0> - constexpr TEnum& operator &= (TEnum& l, TEnum r) noexcept - { - return l = (l & r); - } - - template , int> = 0> - constexpr TEnum operator | (TEnum l, TEnum r) noexcept - { - using etype = std::underlying_type_t; - return static_cast(static_cast(l) | static_cast(r)); - } - - template , int> = 0> - constexpr TEnum& operator |= (TEnum& l, TEnum r) noexcept - { - return l = (l | r); - } - - template , int> = 0> - constexpr TEnum operator ~ (TEnum r) noexcept - { - using etype = std::underlying_type_t; - return static_cast (~static_cast(r)); - } - - template , int> = 0> - constexpr TEnum operator ^ (TEnum l, TEnum r) noexcept - { - using etype = std::underlying_type_t; - return static_cast(static_cast(l) ^ static_cast(r)); - } - - template , int> = 0> - constexpr TEnum& operator ^= (TEnum& l, TEnum r) noexcept - { - return l = (l ^ r); - } -} diff --git a/src/native/clr/include/shared/helpers.hh b/src/native/clr/include/shared/helpers.hh deleted file mode 100644 index 22e29b40f25..00000000000 --- a/src/native/clr/include/shared/helpers.hh +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -using namespace std::string_view_literals; - -namespace xamarin::android -{ - namespace detail { - template - concept TPointer = requires { std::is_pointer_v; }; - } - - class [[gnu::visibility("hidden")]] Helpers - { - public: - template - [[gnu::always_inline]] - static auto add_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret - { - constexpr bool DoNotLogLocation = false; - Ret ret; - - if (__builtin_add_overflow (a, b, &ret)) [[unlikely]] { - // It will leak memory, but it's fine, we're exiting the app anyway - char *message = nullptr; - int n = asprintf (&message, "Integer overflow on addition at %s:%u", sloc.file_name (), sloc.line ()); - abort_application (n == -1 ? "Integer overflow on addition" : message, DoNotLogLocation, sloc); - } - - return ret; - } - - template - [[gnu::always_inline]] - static auto multiply_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret - { - constexpr bool DoNotLogLocation = false; - Ret ret; - - if (__builtin_mul_overflow (a, b, &ret)) [[unlikely]] { - // It will leak memory, but it's fine, we're exiting the app anyway - char *message = nullptr; - int n = asprintf (&message, "Integer overflow on multiplication at %s:%u", sloc.file_name (), sloc.line ()); - abort_application (n == -1 ? "Integer overflow on multiplication" : message, DoNotLogLocation, sloc); - } - - return ret; - } - - [[noreturn]] - static void abort_application (LogCategories category, const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; - - [[noreturn]] - static void abort_application (LogCategories category, std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (category, message.c_str (), log_location, sloc); - } - - [[noreturn]] - static void abort_application (LogCategories category, std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (category, message.data (), log_location, sloc); - } - - [[noreturn]] - static void abort_application (const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (LOG_DEFAULT, message, log_location, sloc); - } - - [[noreturn]] - static void abort_application (std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (LOG_DEFAULT, message.c_str (), log_location, sloc); - } - - [[noreturn]] - static void abort_application (std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (LOG_DEFAULT, message.data (), log_location, sloc); - } - }; - - template [[gnu::always_inline]] - static inline constexpr auto pointer_add (TPtr ptr, size_t offset) noexcept -> TRet - { - return reinterpret_cast(reinterpret_cast(ptr) + offset); - } - - [[gnu::always_inline]] - static inline constexpr auto optional_string (const char* s, const char *replacement = nullptr) noexcept -> const char* - { - if (s != nullptr) [[likely]] { - return s; - } - - return replacement == nullptr ? "" : replacement; - } -} diff --git a/src/native/clr/include/shared/log_level.hh b/src/native/clr/include/shared/log_level.hh deleted file mode 100644 index 66b1cae5097..00000000000 --- a/src/native/clr/include/shared/log_level.hh +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "java-interop-logger.h" -#include "log_level.hh" - -// We redeclare macros here -#if defined(log_debug) -#undef log_debug -#endif - -#if defined(log_info) -#undef log_info -#endif - -#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ - do { \ - if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ - } \ - } while (0) - -// -// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec -// - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -namespace xamarin::android { - // 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; -} - -template [[gnu::always_inline]] -static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Debug, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Info, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); -} - -extern unsigned int log_categories; diff --git a/src/native/clr/include/shared/log_types.hh b/src/native/clr/include/shared/log_types.hh index 656146ec203..0821ef59077 100644 --- a/src/native/clr/include/shared/log_types.hh +++ b/src/native/clr/include/shared/log_types.hh @@ -6,7 +6,7 @@ #include #include "java-interop-logger.h" -#include "log_level.hh" +#include // We redeclare macros here #if defined(log_debug) diff --git a/src/native/clr/include/shared/xxhash.hh b/src/native/clr/include/shared/xxhash.hh deleted file mode 100644 index 32365aceab0..00000000000 --- a/src/native/clr/include/shared/xxhash.hh +++ /dev/null @@ -1,194 +0,0 @@ -#pragma once - -#include - -#if INTPTR_MAX == INT64_MAX -#define XXH_NO_STREAM -#define XXH_INLINE_ALL -#define XXH_NAMESPACE xaInternal_ -#include -#include -#endif - -// -// Based on original code at https://github.com/ekpyron/xxhashct -// -// Original code license: -// - -/** -* MIT License -* -* Copyright (c) 2021 Zachary Arnaise -* -* 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 -#include - -namespace xamarin::android -{ - class xxhash32 final - { - static constexpr uint32_t PRIME1 = 0x9E3779B1U; - static constexpr uint32_t PRIME2 = 0x85EBCA77U; - static constexpr uint32_t PRIME3 = 0xC2B2AE3DU; - static constexpr uint32_t PRIME4 = 0x27D4EB2FU; - static constexpr uint32_t PRIME5 = 0x165667B1U; - - public: - // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily - // understood and to run compile-time algorithm correctness tests - template - [[gnu::always_inline]] - static constexpr auto hash (const char *input, size_t len) noexcept -> uint32_t - { - return finalize ( - (len >= 16 ? h16bytes (input, len) : Seed + PRIME5) + static_cast(len), - (input) + (len & ~0xFU), - len & 0xF - ); - } - - template - [[gnu::always_inline]] - static constexpr auto hash (const char (&input)[Size]) noexcept -> uint32_t - { - return hash (input, Size - 1); - } - - template - [[gnu::always_inline]] - static constexpr auto hash (std::string_view const& input) noexcept -> uint32_t - { - return hash (input.data (), input.length ()); - } - - private: - // 32-bit rotate left. - template [[gnu::always_inline]] - static constexpr auto rotl (uint32_t x) noexcept -> uint32_t - { - return ((x << Bits) | (x >> (32 - Bits))); - } - - // Normal stripe processing routine. - [[gnu::always_inline]] - static constexpr auto round (uint32_t acc, const uint32_t input) noexcept -> uint32_t - { - return rotl<13> (acc + (input * PRIME2)) * PRIME1; - } - - template [[gnu::always_inline]] - static constexpr auto avalanche_step (const uint32_t h) noexcept -> uint32_t - { - return (h ^ (h >> RShift)) * Prime; - } - - // Mixes all bits to finalize the hash. - [[gnu::always_inline]] - static constexpr auto avalanche (const uint32_t h) noexcept -> uint32_t - { - return - avalanche_step<16, 1> ( - avalanche_step<13, PRIME3> ( - avalanche_step <15, PRIME2> (h) - ) - ); - } - - // little-endian version: all our target platforms are little-endian - [[gnu::always_inline]] - static constexpr auto endian32 (const char *v) noexcept -> uint32_t - { - return - static_cast(static_cast(v[0])) | - (static_cast(static_cast(v[1])) << 8) | - (static_cast(static_cast(v[2])) << 16) | - (static_cast(static_cast(v[3])) << 24); - } - - [[gnu::always_inline]] - static constexpr auto fetch32 (const char *p, const uint32_t v) noexcept -> uint32_t - { - return round (v, endian32 (p)); - } - - // Processes the last 0-15 bytes of p. - [[gnu::always_inline]] - static constexpr auto finalize (const uint32_t h, const char *p, size_t len) noexcept -> uint32_t - { - return - (len >= 4) ? finalize (rotl<17> (h + (endian32 (p) * PRIME3)) * PRIME4, p + 4, len - 4) : - (len > 0) ? finalize (rotl<11> (h + (static_cast(*p) * PRIME5)) * PRIME1, p + 1, len - 1) : - avalanche (h); - } - - [[gnu::always_inline]] - static constexpr auto h16bytes (const char *p, size_t len, const uint32_t v1, const uint32_t v2, const uint32_t v3, const uint32_t v4) noexcept -> uint32_t - { - return - (len >= 16) ? h16bytes (p + 16, len - 16, fetch32 (p, v1), fetch32 (p+4, v2), fetch32 (p+8, v3), fetch32 (p+12, v4)) : - rotl<1> (v1) + rotl<7> (v2) + rotl<12> (v3) + rotl<18> (v4); - } - - // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily - // understood - template - [[gnu::always_inline]] - static constexpr auto h16bytes (const char *p, size_t len) noexcept -> uint32_t - { - return h16bytes(p, len, Seed + PRIME1 + PRIME2, Seed + PRIME2, Seed, Seed - PRIME1); - } - }; - -#if INTPTR_MAX == INT64_MAX - class xxhash64 final - { - public: - [[gnu::always_inline]] - static auto hash (const char *p, size_t len) noexcept -> XXH64_hash_t - { - return XXH3_64bits (static_cast(p), len); - } - - [[gnu::always_inline]] - static consteval auto hash (std::string_view const& input) noexcept -> XXH64_hash_t - { - return constexpr_xxh3::XXH3_64bits_const (input.data (), input.length ()); - } - - // The C XXH64_64bits function from xxhash.h is not `constexpr` or `consteval`, so we cannot call it here. - // At the same time, at build time performance is not that important, so we call the "unoptmized" `consteval` - // C++ implementation here - template [[gnu::always_inline]] - static consteval auto hash (const char (&input)[Size]) noexcept -> XXH64_hash_t - { - return constexpr_xxh3::XXH3_64bits_const (input); - } - }; - - using hash_t = XXH64_hash_t; - using xxhash = xxhash64; -#else - using hash_t = uint32_t; - using xxhash = xxhash32; -#endif -} diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index d330071c32b..be8c30541e0 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -6,7 +6,7 @@ #include #include -#include "shared/xxhash.hh" +#include static constexpr uint64_t FORMAT_TAG = 0x00045E6972616D58; // 'Xmari^XY' where XY is the format version static constexpr uint32_t COMPRESSED_DATA_MAGIC = 0x5A4C4158; // 'XALZ', little-endian diff --git a/src/native/common/include/shared/helpers.hh b/src/native/common/include/shared/helpers.hh index 587c48a7f76..22e29b40f25 100644 --- a/src/native/common/include/shared/helpers.hh +++ b/src/native/common/include/shared/helpers.hh @@ -6,7 +6,6 @@ #include #include -#include "platform-compat.hh" using namespace std::string_view_literals; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 2cb51ec75e2..95c36da3f3c 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -581,7 +581,7 @@ EmbeddedAssemblies::zip_extract_cd_info (std::array const& buf } template -force_inline bool +[[gnu::always_inline]] bool EmbeddedAssemblies::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index bbb91157b10..f3447a69840 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -21,12 +21,12 @@ #include "archive-dso-stub-config.hh" #include "log_types.hh" -#include "strings.hh" +#include #include "xamarin-app.hh" #include #include "cppcompat.hh" #include "shared-constants.hh" -#include "xxhash.hh" +#include #include "util.hh" #include diff --git a/src/native/mono/monodroid/monodroid-glue-internal.hh b/src/native/mono/monodroid/monodroid-glue-internal.hh index 2d4f84276b8..2708ac58205 100644 --- a/src/native/mono/monodroid/monodroid-glue-internal.hh +++ b/src/native/mono/monodroid/monodroid-glue-internal.hh @@ -13,6 +13,7 @@ #include #include "monodroid-dl.hh" #include +#include #include #include diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 135c296a61a..26547c8e476 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -774,7 +774,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks return domain; } -force_inline void +[[gnu::always_inline]] void MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info) noexcept { info->klass = klass; @@ -799,7 +799,7 @@ MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJava } } -force_inline void +[[gnu::always_inline]] void MonodroidRuntime::lookup_bridge_info (MonoImage *image, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info) noexcept { lookup_bridge_info ( @@ -1302,7 +1302,7 @@ MonodroidRuntime::typemap_managed_to_java (MonoReflectionType *type, const uint8 } #endif // !def RELEASE -force_inline void +[[gnu::always_inline]] void MonodroidRuntime::setup_mono_tracing (std::unique_ptr const& mono_log_mask, bool have_log_assembly, bool have_log_gc) noexcept { constexpr std::string_view MASK_ASM { "asm" }; @@ -1375,7 +1375,7 @@ MonodroidRuntime::setup_mono_tracing (std::unique_ptr const& mono_log_ma mono_trace_set_mask_string (input_log_mask.get ()); } -force_inline void +[[gnu::always_inline]] void MonodroidRuntime::install_logging_handlers () noexcept { mono_trace_set_log_handler (mono_log_handler, nullptr); @@ -1607,7 +1607,7 @@ Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, ); } -force_inline void +[[gnu::always_inline]] void MonodroidRuntime::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods) noexcept { size_t total_time_index; diff --git a/src/native/mono/runtime-base/jni-wrappers.hh b/src/native/mono/runtime-base/jni-wrappers.hh deleted file mode 100644 index 679aed3df59..00000000000 --- a/src/native/mono/runtime-base/jni-wrappers.hh +++ /dev/null @@ -1,209 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace xamarin::android -{ - class jstring_array_wrapper; - - class jstring_wrapper - { - public: - explicit jstring_wrapper (JNIEnv *_env) noexcept - : env (_env), - jstr (nullptr) - { - abort_if_invalid_pointer_argument (_env, "_env"); - } - - explicit jstring_wrapper (JNIEnv *_env, const jobject jo) noexcept - : env (_env), - jstr (reinterpret_cast (jo)) - { - abort_if_invalid_pointer_argument (_env, "_env"); - } - - explicit jstring_wrapper (JNIEnv *_env, const jstring js) noexcept - : env (_env), - jstr (js) - { - abort_if_invalid_pointer_argument (_env, "_env"); - } - - jstring_wrapper (const jstring_wrapper&) = delete; - - ~jstring_wrapper () noexcept - { - release (); - } - - jstring_wrapper& operator=(const jstring_wrapper&) = delete; - - bool hasValue () noexcept - { - return jstr != nullptr; - } - - private: - [[gnu::always_inline]] - void ensure_cstr () noexcept - { - if (cstr != nullptr || env == nullptr) { - return; - } - - cstr = env->GetStringUTFChars (jstr, nullptr); - } - - public: - const char* get_cstr () noexcept - { - if (jstr == nullptr) { - return nullptr; - } - - ensure_cstr (); - return cstr; - } - - [[gnu::always_inline]] - const std::string_view get_string_view () noexcept - { - if (jstr == nullptr) { - return {}; - } - - ensure_cstr (); - return {cstr}; - } - - jstring_wrapper& operator= (const jobject new_jo) noexcept - { - assign (reinterpret_cast (new_jo)); - return *this; - } - - jstring_wrapper& operator= (const jstring new_js) noexcept - { - assign (new_js); - return *this; - } - - protected: - void release () noexcept - { - if (jstr == nullptr || cstr == nullptr || env == nullptr) { - return; - } - env->ReleaseStringUTFChars (jstr, cstr); - jobjectRefType type = env->GetObjectRefType (jstr); - switch (type) { - case JNILocalRefType: - env->DeleteLocalRef (jstr); - break; - - case JNIGlobalRefType: - env->DeleteGlobalRef (jstr); - break; - - case JNIWeakGlobalRefType: - env->DeleteWeakGlobalRef (jstr); - break; - - case JNIInvalidRefType: // To hush compiler warning - break; - } - - jstr = nullptr; - cstr = nullptr; - } - - void assign (const jstring new_js) noexcept - { - release (); - if (new_js == nullptr) { - return; - } - - jstr = new_js; - cstr = nullptr; - } - - friend class jstring_array_wrapper; - - private: - jstring_wrapper () - : env (nullptr), - jstr (nullptr) - {} - - private: - JNIEnv *env; - jstring jstr; - const char *cstr = nullptr; - }; - - class jstring_array_wrapper - { - public: - explicit jstring_array_wrapper (JNIEnv *_env) noexcept - : jstring_array_wrapper(_env, nullptr) - {} - - explicit jstring_array_wrapper (JNIEnv *_env, jobjectArray _arr) - : env (_env), - arr (_arr) - { - abort_if_invalid_pointer_argument (_env, "_env"); - if (_arr != nullptr) { - len = static_cast(_env->GetArrayLength (_arr)); - if (len > sizeof (static_wrappers) / sizeof (jstring_wrapper)) { - wrappers = new jstring_wrapper [len]; - } else { - wrappers = static_wrappers; - } - } else { - len = 0; - wrappers = nullptr; - } - } - - ~jstring_array_wrapper () noexcept - { - if (wrappers != nullptr && wrappers != static_wrappers) { - delete[] wrappers; - } - } - - size_t get_length () const noexcept - { - return len; - } - - jstring_wrapper& operator[] (size_t index) noexcept - { - if (index >= len) { - return invalid_wrapper; - } - - if (wrappers [index].env == nullptr) { - wrappers [index].env = env; - wrappers [index].jstr = reinterpret_cast (env->GetObjectArrayElement (arr, static_cast(index))); - } - - return wrappers [index]; - } - - private: - JNIEnv *env; - jobjectArray arr; - size_t len; - jstring_wrapper *wrappers; - jstring_wrapper static_wrappers[5]; - jstring_wrapper invalid_wrapper; - }; -} diff --git a/src/native/mono/runtime-base/logger.cc b/src/native/mono/runtime-base/logger.cc index 92c3137cd7a..256f6f2b030 100644 --- a/src/native/mono/runtime-base/logger.cc +++ b/src/native/mono/runtime-base/logger.cc @@ -11,8 +11,8 @@ #include #include "android-system.hh" -#include "cpp-util.hh" -#include "log_level.hh" +#include +#include #include "logger.hh" #include "shared-constants.hh" #include "util.hh" diff --git a/src/native/mono/runtime-base/search.hh b/src/native/mono/runtime-base/search.hh deleted file mode 100644 index c6c3311795f..00000000000 --- a/src/native/mono/runtime-base/search.hh +++ /dev/null @@ -1,60 +0,0 @@ -// Dear Emacs, this is a -*- C++ -*- header -#pragma once - -#include - -#include - -namespace xamarin::android { - class Search final - { - public: - template - [[gnu::always_inline]] - static ssize_t binary_search (hash_t key, const T *arr, size_t n) noexcept - { - static_assert (equal != nullptr, "equal is a required template parameter"); - static_assert (less_than != nullptr, "less_than is a required template parameter"); - - ssize_t left = -1z; - ssize_t right = static_cast(n); - - while (right - left > 1) { - ssize_t middle = (left + right) >> 1u; - if (less_than (arr[middle], key)) { - left = middle; - } else { - right = middle; - } - } - - return equal (arr[right], key) ? right : -1z; - } - - [[gnu::always_inline]] - static ssize_t binary_search (hash_t key, const hash_t *arr, size_t n) noexcept - { - auto equal = [](hash_t const& entry, hash_t key) -> bool { return entry == key; }; - auto less_than = [](hash_t const& entry, hash_t key) -> bool { return entry < key; }; - - return binary_search (key, arr, n); - } - - [[gnu::always_inline]] - static ptrdiff_t binary_search_branchless (hash_t x, const hash_t *arr, uint32_t len) noexcept - { - const hash_t *base = arr; - while (len > 1) { - uint32_t half = len >> 1; - // __builtin_prefetch(&base[(len - half) / 2]); - // __builtin_prefetch(&base[half + (len - half) / 2]); - base = (base[half] < x ? &base[half] : base); - len -= half; - } - - //return *(base + (*base < x)); - ptrdiff_t ret = (base + (*base < x)) - arr; - return arr[ret] == x ? ret : -1; - } - }; -} diff --git a/src/native/mono/runtime-base/strings.hh b/src/native/mono/runtime-base/strings.hh deleted file mode 100644 index b076e4f5ca9..00000000000 --- a/src/native/mono/runtime-base/strings.hh +++ /dev/null @@ -1,964 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(XA_HOST_CLR) -#include -#else -#include - -using Constants = xamarin::android::internal::SharedConstants; -#endif - -namespace xamarin::android { - static constexpr size_t SENSIBLE_TYPE_NAME_LENGTH = 128uz; - static constexpr size_t SENSIBLE_PATH_MAX = 256uz; - -#if DEBUG - static constexpr bool BoundsCheck = true; -#else - static constexpr bool BoundsCheck = false; -#endif - - enum class string_segment_error - { - index_out_of_range, - }; - - static inline auto to_string (string_segment_error error) -> std::string_view const - { - using std::operator""sv; - - switch (error) { - case string_segment_error::index_out_of_range: - return "Index out of range"sv; - - default: - return "Unknown error"sv; - } - } - - class string_segment - { - public: - [[gnu::always_inline]] - auto initialized () const noexcept -> bool - { - return !_fresh; - } - - [[gnu::always_inline]] - auto start () const noexcept -> const char* - { - return _start; - } - - [[gnu::always_inline]] - auto at (size_t offset) const noexcept -> std::expected - { - if (offset >= length ()) { - return std::unexpected (string_segment_error::index_out_of_range); - } - - return _start + offset; - } - - [[gnu::always_inline]] - auto length () const noexcept -> size_t - { - return _length; - } - - [[gnu::always_inline]] - auto empty () const noexcept -> bool - { - return length () == 0; - } - - [[gnu::always_inline]] - auto equal (const char *s) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return equal (s, strlen (s)); - } - - [[gnu::always_inline]] - auto equal (const char *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - if (length () != s_length) { - return false; - } - - if (!can_access (s_length)) [[unlikely]] { - return false; - } - - if (length () == 0) { - return true; - } - - return memcmp (_start, s, length ()) == 0; - } - - template [[gnu::always_inline]] - auto equal (const char (&s)[Size]) noexcept -> bool - { - return equal (s, Size - 1); - } - - [[gnu::always_inline]] - auto equal (std::string_view const& s) noexcept -> bool - { - return equal (s.data (), s.length ()); - } - - [[gnu::always_inline]] - auto starts_with_c (const char *s) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return starts_with (s, strlen (s)); - } - - [[gnu::always_inline]] - auto starts_with (const char *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr || !can_access (s_length)) { - return false; - } - - if (length () < s_length) { - return false; - } - - return memcmp (start (), s, s_length) == 0; - } - - template [[gnu::always_inline]] - auto starts_with (const char (&s)[Size]) const noexcept -> bool - { - return starts_with (s, Size - 1); - } - - [[gnu::always_inline]] - auto starts_with (std::string_view const& s) const noexcept -> bool - { - return starts_with (s.data (), s.length ()); - } - - [[gnu::always_inline]] - auto has_at (const char ch, size_t index) const noexcept -> bool - { - if (!can_access (index)) { - return false; - } - - return start ()[index] == ch; - } - - [[gnu::always_inline]] - auto find (const char ch, size_t start_index) const noexcept -> ssize_t - { - if (!can_access (start_index)) { - return -1; - } - - while (start_index <= length ()) { - if (start ()[start_index] == ch) { - return static_cast(start_index); - } - start_index++; - } - - return -1; - } - - template [[gnu::always_inline]] - auto to_integer (T &val, size_t start_index = 0uz, int base = 10) const noexcept -> bool - { - static_assert (std::is_integral_v); - constexpr T min = std::numeric_limits::min (); - constexpr T max = std::numeric_limits::max (); - using integer = typename std::conditional, int64_t, uint64_t>::type; - - if (length () == 0uz) { - return false; - } - - if (!can_access (start_index)) { - log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); - return false; - } - - // FIXME: this is less than ideal... we shouldn't need another buffer here - size_t slen = length () - start_index; - char s[slen + 1]; - - memcpy (s, start () + start_index, slen); - s[slen] = '\0'; - - integer ret; - char *endp; - bool out_of_range; - errno = 0; - if constexpr (std::is_signed_v) { - ret = strtoll (s, &endp, base); - out_of_range = ret < min || ret > max; - } else { - ret = strtoull (s, &endp, base); - out_of_range = ret > max; - } - - if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); - return false; - } - - if (endp == s) { - log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); - return false; - } - - if (*endp != '\0') { - log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); - return false; - } - - val = static_cast(ret); - return true; - } - - private: - [[gnu::always_inline]] - auto can_access (size_t index) const noexcept -> bool - { - if (!initialized () || start () == nullptr) [[unlikely]] { - return false; - } - - if (index > length ()) { - return false; - } - - return true; - } - - protected: - size_t _last_index = 0uz; - bool _fresh = true; - const char *_start = nullptr; - size_t _length = 0uz; - - template friend class string_base; - }; - - template - class local_storage - { - protected: - using LocalStoreArray = std::array; - - public: - static constexpr bool has_resize = HasResize; - - public: - explicit local_storage (size_t size) noexcept - { - static_assert (MaxStackSize > 0, "MaxStackSize must be more than 0"); - init_store (size < MaxStackSize ? MaxStackSize : size); - } - - virtual ~local_storage () - { - free_store (); - } - - auto get () noexcept -> T* - { - return allocated_store == nullptr ? local_store.data () : allocated_store; - } - - auto get () const noexcept -> const T* - { - return allocated_store == nullptr ? local_store.data () : allocated_store; - } - - auto size () const noexcept -> size_t - { - return store_size; - } - - protected: - [[gnu::always_inline]] - void init_store (size_t new_size) noexcept - { - if (new_size > MaxStackSize) { - allocated_store = new T[new_size]; - } else { - allocated_store = nullptr; - } - store_size = new_size; - } - - [[gnu::always_inline]] - void free_store () noexcept - { - if (allocated_store == nullptr) { - return; - } - - delete[] allocated_store; - } - - [[gnu::always_inline]] - auto get_local_store () noexcept -> LocalStoreArray& - { - return local_store; - } - - [[gnu::always_inline]] - auto get_allocated_store () noexcept -> T* - { - return allocated_store; - } - - private: - size_t store_size; - LocalStoreArray local_store; - T* allocated_store; - }; - - // This class is meant to provide a *very* thin veneer (by design) over space allocated for *local* buffers - that - // is one which are not meant to survive the exit of the function they are created in. The idea is that the caller - // knows the size of the buffer they need and they want to put the buffer on stack, if it doesn't exceed a certain - // value, or dynamically allocate memory if more is needed. Even though the class could be used on its own, it's - // really meant to be a base for more specialized buffers. There are not many safeguards, by design - the code is - // meant to be performant. This is the reason why the size is static throughout the life of the object, so that we - // can perform as few checks as possible. - - template using static_local_storage_base = local_storage; - - template - class static_local_storage final : public static_local_storage_base - { - using base = static_local_storage_base; - - public: - explicit static_local_storage (size_t initial_size) noexcept - : base (initial_size) - {} - }; - - template using dynamic_local_storage_base = local_storage; - - template - class dynamic_local_storage final : public dynamic_local_storage_base - { - using base = dynamic_local_storage_base; - - public: - explicit dynamic_local_storage (size_t initial_size = 0uz) noexcept - : base (initial_size) - {} - - // - // If `new_size` is smaller than the current size and the dynamic store is allocated, data WILL NOT be - // preserved. - // - // If `new_size` is bigger than the current size bigger than MaxStackSize, data will be copied to the new - // dynamically allocated store - // - // If `new_size` is smaller or equal to `MaxStackSize`, no changes are made unless dynamic store was allocated, - // in which case it will be freed - // - void resize (size_t new_size) noexcept - { - size_t old_size = base::size (); - - if (new_size == old_size) { - return; - } - - if (new_size <= MaxStackSize) { - new_size = MaxStackSize; - base::free_store (); - return; - } - - if (new_size < old_size) { - base::free_store (); - base::init_store (new_size); - return; - } - - T* old_allocated_store = base::get_allocated_store (); - base::init_store (new_size); - - T* new_allocated_store = base::get_allocated_store (); - if (old_allocated_store != nullptr) { - std::memcpy (new_allocated_store, old_allocated_store, old_size); - delete[] old_allocated_store; - return; - } - - std::memcpy (new_allocated_store, base::get_local_store ().data (), MaxStackSize); - } - }; - - template - class string_base - { - protected: - static constexpr TChar NUL = '\0'; - static constexpr TChar ZERO = '0'; - - public: - explicit string_base (size_t initial_size = 0uz) - : buffer (initial_size) - { - // Currently we care only about `char`, maybe in the future we'll add support for `wchar` (if needed) - static_assert (std::is_same_v, "TChar must be an 8-bit character type"); - - clear (); - } - - explicit string_base (const string_segment &token) - : string_base (token.initialized () ? token.length () : 0) - { - if (token.initialized ()) { - assign (token.start (), token.length ()); - } - } - - [[gnu::always_inline]] - auto length () const noexcept -> size_t - { - return idx; - } - - [[gnu::always_inline]] - auto empty () const noexcept -> bool - { - return length () == 0; - } - - [[gnu::always_inline]] - void set_length (size_t new_length) noexcept - { - if (new_length >= buffer.size ()) { - return; - } - - idx = new_length; - terminate (); - } - - [[gnu::always_inline]] - void clear () noexcept - { - set_length (0); - buffer.get ()[0] = NUL; - } - - [[gnu::always_inline]] - void terminate () noexcept - { - buffer.get ()[idx] = NUL; - } - - [[gnu::always_inline]] - auto replace (const TChar c1, const TChar c2) noexcept -> string_base& - { - if (empty ()) { - return *this; - } - - for (size_t i = 0uz; i < length (); i++) { - if (buffer.get ()[i] == c1) { - buffer.get ()[i] = c2; - } - } - - return *this; - } - - [[gnu::always_inline]] - auto append (const TChar* s, size_t length) noexcept -> string_base& - { - if (s == nullptr || length == 0uz) { - return *this; - } - - resize_for_extra (length); - if constexpr (BoundsCheck) { - ensure_have_extra (length); - } - - std::memcpy (buffer.get () + idx, s, length); - idx += length; - buffer.get ()[idx] = NUL; - - return *this; - } - - template - [[gnu::always_inline]] - auto append (string_base const& str) noexcept -> string_base& - { - return append (str.get (), str.length ()); - } - - [[gnu::always_inline]] - auto append (std::string_view const& sv) noexcept -> string_base& - { - return append (sv.data (), sv.length ()); - } - - template [[gnu::always_inline]] - auto append (const char (&s)[Size]) noexcept -> string_base& - { - return append (s, Size - 1); - } - - [[gnu::always_inline]] - auto append_c (const char *s) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - return append (s, strlen (s)); - } - - [[gnu::always_inline]] - auto append (int16_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (buffer.get (), i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint16_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (int32_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint32_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (int64_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint64_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto assign (const TChar* s, size_t length) noexcept -> string_base& - { - idx = 0; - return append (s, length); - } - - [[gnu::always_inline]] - auto assign_c (const TChar* s) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - return assign (s, strlen (s)); - } - - [[gnu::always_inline]] - auto assign (std::string_view const& sv) noexcept -> string_base& - { - return assign (sv.data (), sv.size ()); - } - - [[gnu::always_inline]] - auto assign (std::string const& s) noexcept -> string_base& - { - return assign (s.data (), s.size ()); - } - - template [[gnu::always_inline]] - auto assign (const char (&s)[Size]) noexcept -> string_base& - { - return assign (s, Size - 1); - } - - template - [[gnu::always_inline]] - auto assign (string_base const& str) noexcept -> string_base& - { - return assign (str.get (), str.length ()); - } - - [[gnu::always_inline]] - auto assign (const TChar* s, size_t offset, size_t count) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - if constexpr (BoundsCheck) { - size_t slen = strlen (s); - if (offset + count > slen) { - Helpers::abort_application ("Attempt to assign data from a string exceeds the source string length"); - } - } - - return assign (s + offset, count); - } - - [[gnu::always_inline]] - auto next_token (size_t start_index, const TChar separator, string_segment& token) const noexcept -> bool - { - size_t index; - if (token._fresh) { - token._fresh = false; - token._last_index = start_index; - index = start_index; - } else { - index = token._last_index + 1; - } - - token._start = nullptr; - token._length = 0; - if (token._last_index + 1 >= buffer.size ()) { - return false; - } - - const TChar *start = buffer.get () + index; - const TChar *p = start; - while (*p != NUL) { - if (*p == separator) { - break; - } - p++; - index++; - } - - token._last_index = *p == NUL ? buffer.size () : index; - token._start = start; - token._length = static_cast(p - start); - - return true; - } - - [[gnu::always_inline]] - auto next_token (const char separator, string_segment& token) const noexcept -> bool - { - return next_token (0, separator, token); - } - - [[gnu::always_inline]] - auto index_of (const TChar ch) const noexcept -> ssize_t - { - const TChar *p = buffer.get (); - while (p != nullptr && *p != NUL) { - if (*p == ch) { - return static_cast(p - buffer.get ()); - } - p++; - } - - return -1; - } - - [[gnu::always_inline]] - auto starts_with (const TChar *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr || s_length == 0 || s_length > buffer.size ()) { - return false; - } - - return memcmp (buffer.get (), s, s_length) == 0; - } - - [[gnu::always_inline]] - auto starts_with_c (const char* s) noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return starts_with (s, strlen (s)); - } - - template [[gnu::always_inline]] - auto starts_with (const char (&s)[Size]) noexcept -> bool - { - return starts_with (s, Size - 1); - } - - [[gnu::always_inline]] - auto starts_with (std::string_view const& s) noexcept -> bool - { - return starts_with (s.data (), s.length ()); - } - - [[gnu::always_inline]] - void set_length_after_direct_write (size_t new_length) noexcept - { - set_length (new_length); - terminate (); - } - - [[gnu::always_inline]] - void set_at (size_t index, const TChar ch) noexcept - { - ensure_valid_index (index); - TChar *p = buffer + index; - if (*p == NUL) { - return; - } - - *p = ch; - } - - [[gnu::always_inline]] - auto get_at (size_t index) const noexcept -> const TChar - { - ensure_valid_index (index); - return *(buffer.get () + index); - } - - [[gnu::always_inline]] - auto get_at (size_t index) noexcept -> TChar& - { - ensure_valid_index (index); - return *(buffer.get () + index); - } - - [[gnu::always_inline]] - auto get () const noexcept -> const TChar* - { - return buffer.get (); - } - - [[gnu::always_inline]] - auto get () noexcept -> TChar* - { - return buffer.get (); - } - - [[gnu::always_inline]] - auto size () const noexcept -> size_t - { - return buffer.size (); - } - - [[gnu::always_inline]] - auto operator[] (size_t index) const noexcept -> char - { - return get_at (index); - } - - [[gnu::always_inline]] - auto operator[] (size_t index) noexcept -> char& - { - return get_at (index); - } - - protected: - template [[gnu::always_inline]] - void append_integer (Integer i) noexcept - { - static_assert (std::is_integral_v); - - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - if constexpr (BoundsCheck) { - ensure_have_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - } - - if (i == 0) { - constexpr char zero[] = "0"; - constexpr size_t zero_len = sizeof(zero) - 1uz; - - append (zero, zero_len); - return; - } - - TChar temp_buf[Constants::MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz]; - TChar *p = temp_buf + Constants::MAX_INTEGER_DIGIT_COUNT_BASE10; - *p = NUL; - TChar *end = p; - - uint32_t x; - if constexpr (sizeof(Integer) > 4uz) { - uint64_t y; - - if constexpr (std::is_signed_v) { - y = static_cast(i > 0 ? i : -i); - } else { - y = static_cast(i); - } - while (y > std::numeric_limits::max ()) { - *--p = (y % 10) + ZERO; - y /= 10; - } - x = static_cast(y); - } else { - if constexpr (std::is_signed_v) { - x = static_cast(i > 0 ? i : -i); - } else { - x = static_cast(i); - } - } - - while (x > 0) { - *--p = (x % 10) + ZERO; - x /= 10; - } - - if constexpr (std::is_signed_v) { - if (i < 0) - *--p = '-'; - } - - append (p, static_cast(end - p)); - } - - [[gnu::always_inline]] - void ensure_valid_index (size_t access_index) const noexcept - { - if (access_index < idx && access_index < buffer.size ()) [[likely]] { - return; - } - - char *message = nullptr; - int n = asprintf (&message, "Index %zu is out of range (0 - %zu)", access_index, idx); - Helpers::abort_application (n == -1 ? "Index out of range" : message); - } - - [[gnu::always_inline]] - void ensure_have_extra (size_t length) noexcept - { - size_t needed_space = Helpers::add_with_overflow_check (length, idx + 1); - if (needed_space > buffer.size ()) { - char *message = nullptr; - int n = asprintf ( - &message, - "Attempt to store too much data in a buffer (capacity: %zu; exceeded by: %zu)", - buffer.size (), - needed_space - buffer.size () - ); - Helpers::abort_application (n == -1 ? "Attempt to store too much data in a buffer" : message); - } - } - - [[gnu::always_inline]] - void resize_for_extra (size_t needed_space) noexcept - { - if constexpr (TStorage::has_resize) { - size_t required_space = Helpers::add_with_overflow_check (needed_space, idx + 1uz); - size_t current_size = buffer.size (); - if (required_space > current_size) { - size_t new_size = Helpers::add_with_overflow_check (current_size, (current_size / 2uz)); - new_size = Helpers::add_with_overflow_check (new_size, required_space); - buffer.resize (new_size); - } - } - } - - private: - size_t idx; - TStorage buffer; - }; - - template - class static_local_string : public string_base, TChar> - { - using base = string_base, TChar>; - - public: - explicit static_local_string (size_t initial_size = 0uz) noexcept - : base (initial_size) - {} - - explicit static_local_string (const string_segment &token) noexcept - : base (token) - {} - - template - explicit static_local_string (const char (&str)[N]) - : base (N) - { - append (str); - } - }; - - template - class dynamic_local_string : public string_base, TChar> - { - using base = string_base, TChar>; - - public: - explicit dynamic_local_string (size_t initial_size = 0uz) - : base (initial_size) - {} - - explicit dynamic_local_string (const string_segment &token) noexcept - : base (token) - {} - - template - explicit dynamic_local_string (const char (&str)[N]) - : base (N) - { - base::append (str); - } - - explicit dynamic_local_string (std::string_view const& str) - : base (str.length ()) - { - base::append (str); - } - }; -} diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 3dbdeae10bc..33e9524703f 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -209,7 +209,7 @@ namespace xamarin::android } template - static bool ends_with (internal::string_base const& str, std::array const& end) noexcept + static bool ends_with (string_base const& str, std::array const& end) noexcept { constexpr size_t end_length = N - 1uz; diff --git a/src/native/mono/shared/helpers.cc b/src/native/mono/shared/helpers.cc index 9638b16ebd5..d1a785cc09b 100644 --- a/src/native/mono/shared/helpers.cc +++ b/src/native/mono/shared/helpers.cc @@ -2,7 +2,7 @@ #include #include -#include "helpers.hh" +#include #include "log_types.hh" using namespace xamarin::android; diff --git a/src/native/mono/shared/helpers.hh b/src/native/mono/shared/helpers.hh deleted file mode 100644 index 587c48a7f76..00000000000 --- a/src/native/mono/shared/helpers.hh +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include "platform-compat.hh" - -using namespace std::string_view_literals; - -namespace xamarin::android -{ - namespace detail { - template - concept TPointer = requires { std::is_pointer_v; }; - } - - class [[gnu::visibility("hidden")]] Helpers - { - public: - template - [[gnu::always_inline]] - static auto add_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret - { - constexpr bool DoNotLogLocation = false; - Ret ret; - - if (__builtin_add_overflow (a, b, &ret)) [[unlikely]] { - // It will leak memory, but it's fine, we're exiting the app anyway - char *message = nullptr; - int n = asprintf (&message, "Integer overflow on addition at %s:%u", sloc.file_name (), sloc.line ()); - abort_application (n == -1 ? "Integer overflow on addition" : message, DoNotLogLocation, sloc); - } - - return ret; - } - - template - [[gnu::always_inline]] - static auto multiply_with_overflow_check (P1 a, P2 b, std::source_location sloc = std::source_location::current ()) noexcept -> Ret - { - constexpr bool DoNotLogLocation = false; - Ret ret; - - if (__builtin_mul_overflow (a, b, &ret)) [[unlikely]] { - // It will leak memory, but it's fine, we're exiting the app anyway - char *message = nullptr; - int n = asprintf (&message, "Integer overflow on multiplication at %s:%u", sloc.file_name (), sloc.line ()); - abort_application (n == -1 ? "Integer overflow on multiplication" : message, DoNotLogLocation, sloc); - } - - return ret; - } - - [[noreturn]] - static void abort_application (LogCategories category, const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; - - [[noreturn]] - static void abort_application (LogCategories category, std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (category, message.c_str (), log_location, sloc); - } - - [[noreturn]] - static void abort_application (LogCategories category, std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (category, message.data (), log_location, sloc); - } - - [[noreturn]] - static void abort_application (const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (LOG_DEFAULT, message, log_location, sloc); - } - - [[noreturn]] - static void abort_application (std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (LOG_DEFAULT, message.c_str (), log_location, sloc); - } - - [[noreturn]] - static void abort_application (std::string_view const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept - { - abort_application (LOG_DEFAULT, message.data (), log_location, sloc); - } - }; - - template [[gnu::always_inline]] - static inline constexpr auto pointer_add (TPtr ptr, size_t offset) noexcept -> TRet - { - return reinterpret_cast(reinterpret_cast(ptr) + offset); - } - - [[gnu::always_inline]] - static inline constexpr auto optional_string (const char* s, const char *replacement = nullptr) noexcept -> const char* - { - if (s != nullptr) [[likely]] { - return s; - } - - return replacement == nullptr ? "" : replacement; - } -} diff --git a/src/native/mono/shared/log_functions.cc b/src/native/mono/shared/log_functions.cc index c6d61f54d0d..394ba2a1927 100644 --- a/src/native/mono/shared/log_functions.cc +++ b/src/native/mono/shared/log_functions.cc @@ -4,7 +4,7 @@ #include #include "java-interop-logger.h" -#include "log_level.hh" +#include // Must match the same ordering as LogCategories static constexpr std::array log_names = { diff --git a/src/native/mono/shared/log_level.hh b/src/native/mono/shared/log_level.hh deleted file mode 100644 index fc7a7566910..00000000000 --- a/src/native/mono/shared/log_level.hh +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -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 - }; -} diff --git a/src/native/mono/shared/log_types.hh b/src/native/mono/shared/log_types.hh index 66b1cae5097..53e7fbc97df 100644 --- a/src/native/mono/shared/log_types.hh +++ b/src/native/mono/shared/log_types.hh @@ -6,7 +6,7 @@ #include #include "java-interop-logger.h" -#include "log_level.hh" +#include // We redeclare macros here #if defined(log_debug) diff --git a/src/native/mono/shared/xxhash.hh b/src/native/mono/shared/xxhash.hh deleted file mode 100644 index 32365aceab0..00000000000 --- a/src/native/mono/shared/xxhash.hh +++ /dev/null @@ -1,194 +0,0 @@ -#pragma once - -#include - -#if INTPTR_MAX == INT64_MAX -#define XXH_NO_STREAM -#define XXH_INLINE_ALL -#define XXH_NAMESPACE xaInternal_ -#include -#include -#endif - -// -// Based on original code at https://github.com/ekpyron/xxhashct -// -// Original code license: -// - -/** -* MIT License -* -* Copyright (c) 2021 Zachary Arnaise -* -* 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 -#include - -namespace xamarin::android -{ - class xxhash32 final - { - static constexpr uint32_t PRIME1 = 0x9E3779B1U; - static constexpr uint32_t PRIME2 = 0x85EBCA77U; - static constexpr uint32_t PRIME3 = 0xC2B2AE3DU; - static constexpr uint32_t PRIME4 = 0x27D4EB2FU; - static constexpr uint32_t PRIME5 = 0x165667B1U; - - public: - // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily - // understood and to run compile-time algorithm correctness tests - template - [[gnu::always_inline]] - static constexpr auto hash (const char *input, size_t len) noexcept -> uint32_t - { - return finalize ( - (len >= 16 ? h16bytes (input, len) : Seed + PRIME5) + static_cast(len), - (input) + (len & ~0xFU), - len & 0xF - ); - } - - template - [[gnu::always_inline]] - static constexpr auto hash (const char (&input)[Size]) noexcept -> uint32_t - { - return hash (input, Size - 1); - } - - template - [[gnu::always_inline]] - static constexpr auto hash (std::string_view const& input) noexcept -> uint32_t - { - return hash (input.data (), input.length ()); - } - - private: - // 32-bit rotate left. - template [[gnu::always_inline]] - static constexpr auto rotl (uint32_t x) noexcept -> uint32_t - { - return ((x << Bits) | (x >> (32 - Bits))); - } - - // Normal stripe processing routine. - [[gnu::always_inline]] - static constexpr auto round (uint32_t acc, const uint32_t input) noexcept -> uint32_t - { - return rotl<13> (acc + (input * PRIME2)) * PRIME1; - } - - template [[gnu::always_inline]] - static constexpr auto avalanche_step (const uint32_t h) noexcept -> uint32_t - { - return (h ^ (h >> RShift)) * Prime; - } - - // Mixes all bits to finalize the hash. - [[gnu::always_inline]] - static constexpr auto avalanche (const uint32_t h) noexcept -> uint32_t - { - return - avalanche_step<16, 1> ( - avalanche_step<13, PRIME3> ( - avalanche_step <15, PRIME2> (h) - ) - ); - } - - // little-endian version: all our target platforms are little-endian - [[gnu::always_inline]] - static constexpr auto endian32 (const char *v) noexcept -> uint32_t - { - return - static_cast(static_cast(v[0])) | - (static_cast(static_cast(v[1])) << 8) | - (static_cast(static_cast(v[2])) << 16) | - (static_cast(static_cast(v[3])) << 24); - } - - [[gnu::always_inline]] - static constexpr auto fetch32 (const char *p, const uint32_t v) noexcept -> uint32_t - { - return round (v, endian32 (p)); - } - - // Processes the last 0-15 bytes of p. - [[gnu::always_inline]] - static constexpr auto finalize (const uint32_t h, const char *p, size_t len) noexcept -> uint32_t - { - return - (len >= 4) ? finalize (rotl<17> (h + (endian32 (p) * PRIME3)) * PRIME4, p + 4, len - 4) : - (len > 0) ? finalize (rotl<11> (h + (static_cast(*p) * PRIME5)) * PRIME1, p + 1, len - 1) : - avalanche (h); - } - - [[gnu::always_inline]] - static constexpr auto h16bytes (const char *p, size_t len, const uint32_t v1, const uint32_t v2, const uint32_t v3, const uint32_t v4) noexcept -> uint32_t - { - return - (len >= 16) ? h16bytes (p + 16, len - 16, fetch32 (p, v1), fetch32 (p+4, v2), fetch32 (p+8, v3), fetch32 (p+12, v4)) : - rotl<1> (v1) + rotl<7> (v2) + rotl<12> (v3) + rotl<18> (v4); - } - - // We don't use any special seed in XA, the template parameter is just to keep the algorithm more easily - // understood - template - [[gnu::always_inline]] - static constexpr auto h16bytes (const char *p, size_t len) noexcept -> uint32_t - { - return h16bytes(p, len, Seed + PRIME1 + PRIME2, Seed + PRIME2, Seed, Seed - PRIME1); - } - }; - -#if INTPTR_MAX == INT64_MAX - class xxhash64 final - { - public: - [[gnu::always_inline]] - static auto hash (const char *p, size_t len) noexcept -> XXH64_hash_t - { - return XXH3_64bits (static_cast(p), len); - } - - [[gnu::always_inline]] - static consteval auto hash (std::string_view const& input) noexcept -> XXH64_hash_t - { - return constexpr_xxh3::XXH3_64bits_const (input.data (), input.length ()); - } - - // The C XXH64_64bits function from xxhash.h is not `constexpr` or `consteval`, so we cannot call it here. - // At the same time, at build time performance is not that important, so we call the "unoptmized" `consteval` - // C++ implementation here - template [[gnu::always_inline]] - static consteval auto hash (const char (&input)[Size]) noexcept -> XXH64_hash_t - { - return constexpr_xxh3::XXH3_64bits_const (input); - } - }; - - using hash_t = XXH64_hash_t; - using xxhash = xxhash64; -#else - using hash_t = uint32_t; - using xxhash = xxhash32; -#endif -} diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index e64c42750c8..85de1c000ed 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -13,7 +13,7 @@ #include "util.hh" #include "debug-app-helper.hh" #include "shared-constants.hh" -#include "jni-wrappers.hh" +#include #include "log_types.hh" using namespace xamarin::android; From 93dd85e16ff51262b805eb7d73aafb47c6ee580d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 14 Feb 2025 17:55:51 +0100 Subject: [PATCH 106/143] Fix package manager registration for CoreCLR --- CLR-Host-Notes.md | 46 +++++++++++++++++++ src/Mono.Android/Android.Runtime/JNIEnv.cs | 17 ++++++- .../Utilities/ManifestDocument.cs | 10 ++-- .../java/mono/android/MonoPackageManager.java | 1 + .../mono/android/clr/MonoPackageManager.java | 7 ++- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/CLR-Host-Notes.md b/CLR-Host-Notes.md index 5c623e14f15..82ce3917bb6 100644 --- a/CLR-Host-Notes.md +++ b/CLR-Host-Notes.md @@ -37,3 +37,49 @@ be shared between all targets, which then can (if needed) translate it to the ta Runtime currently calls `abort()` in several places. This should probably become part of the host contract instead. Being part of the contract, the target platform could implement process termination on `abort()` in a uniform way (includes platform-specific logging, preparation etc) + +## Issues and workarounds + +### Trimmer issue (as of 14.02.2025) + +It appears the trimmer removes a bit too much at this point. In order to make the application run with trimming, one +needs to add the following to their .csproj (solution found by Ivan Povazan): + +```xml + + + +``` + +and put the following in the `MyRoots.xml` file: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 9a62ac20bbc..6056c6ecc8d 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -77,6 +77,11 @@ internal static bool ShouldWrapJavaException (Java.Lang.Throwable? t, [CallerMem return wrap; } + static void MonoDroidUnhandledException (Exception ex) + { + RuntimeNativeMethods.monodroid_unhandled_exception (ex); + } + internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPtr, IntPtr javaExceptionPtr) { if (!JNIEnvInit.PropagateExceptions) @@ -95,7 +100,17 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt Logger.Log (LogLevel.Info, "MonoDroid", "UNHANDLED EXCEPTION:"); Logger.Log (LogLevel.Info, "MonoDroid", javaException.ToString ()); - RuntimeNativeMethods.monodroid_unhandled_exception (innerException ?? javaException); + switch (JNIEnvInit.RuntimeType) { + case DotNetRuntimeType.MonoVM: + MonoDroidUnhandledException (innerException ?? javaException); + break; + case DotNetRuntimeType.CoreCLR: + // TODO: what to do here? + break; + + default: + throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported"); + } } catch (Exception e) { Logger.Log (LogLevel.Error, "monodroid", "Exception thrown while raising AppDomain.UnhandledException event: " + e.ToString ()); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index 283cad40670..f24db218d69 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -673,10 +673,12 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L IList AddMonoRuntimeProviders (XElement app) { - if (AndroidRuntime != AndroidRuntime.MonoVM && AndroidRuntime != AndroidRuntime.CoreCLR) { - //TODO: implement provider logic for non-Mono runtimes - return []; - } + (string packageName, string className) = AndroidRuntime switch { + AndroidRuntime.MonoVM => ("mono", "MonoRuntimeProvider"), + AndroidRuntime.CoreCLR => ("mono", "MonoRuntimeProvider"), + AndroidRuntime.NativeAOT => ("net.dot.jni.nativeaot", "NativeAotRuntimeProvider"), + _ => throw new NotSupportedException ($"Internal error: unsupported runtime type: {AndroidRuntime}") + }; app.Add (CreateMonoRuntimeProvider ($"{packageName}.{className}", null, --AppInitOrder)); diff --git a/src/java-runtime/java/mono/android/MonoPackageManager.java b/src/java-runtime/java/mono/android/MonoPackageManager.java index 9878c0d8e6c..273612cd957 100644 --- a/src/java-runtime/java/mono/android/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/MonoPackageManager.java @@ -27,6 +27,7 @@ public class MonoPackageManager { public static void LoadApplication (Context context) { + Log.w ("XAMONO", "MonoPackageManager.LoadApplication: start"); synchronized (lock) { android.content.pm.ApplicationInfo runtimePackage = context.getApplicationInfo (); String[] apks = null; diff --git a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java index cb07e7fba04..48b1603483b 100644 --- a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java @@ -18,14 +18,13 @@ import mono.android.Runtime; import mono.android.DebugRuntime; import mono.android.BuildConfig; +import net.dot.android.ApplicationRegistration; public class MonoPackageManager { static Object lock = new Object (); static boolean initialized; - static android.content.Context Context; - public static void LoadApplication (Context context) { Log.w ("XACLR", "MonoPackageManager.LoadApplication: start"); @@ -42,7 +41,7 @@ public static void LoadApplication (Context context) } if (context instanceof android.app.Application) { - Context = context; + ApplicationRegistration.Context = context; } if (!initialized) { Log.w ("XACLR", "MonoPackageManager.LoadApplication: initializing"); @@ -89,7 +88,7 @@ public static void LoadApplication (Context context) ); Log.w ("XACLR", "MonoPackageManager.LoadApplication: call registerApplications"); - net.dot.android.ApplicationRegistration.registerApplications (); + ApplicationRegistration.registerApplications (); Log.w ("XACLR", "MonoPackageManager.LoadApplication: initialized"); initialized = true; From 092b1319ee5cb5b62e38479636ba476f85bba863 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 14 Feb 2025 18:19:13 +0100 Subject: [PATCH 107/143] Fix pinvoke generator --- build-tools/scripts/generate-pinvoke-tables.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-tools/scripts/generate-pinvoke-tables.sh b/build-tools/scripts/generate-pinvoke-tables.sh index 5099cdea0b1..dbf70afd352 100755 --- a/build-tools/scripts/generate-pinvoke-tables.sh +++ b/build-tools/scripts/generate-pinvoke-tables.sh @@ -77,7 +77,7 @@ function generate() local TARGET="${SOURCE_DIR}/${TARGET_FILE}" local DIFF="${SOURCE_DIR}/${DIFF_FILE}" - ${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 -I${INCLUDE_DIR} "${SOURCE}" -o "${BINARY}" + ${COMPILER} -O2 -std=c++20 -I${EXTERNAL_DIR} -I${EXTERNAL_DIR}/constexpr-xxh3 -I${INCLUDE_DIR} -I${NATIVE_DIR}/common/include "${SOURCE}" -o "${BINARY}" "${BINARY}" "${RESULT}" FILES_DIFFER="no" From 39d375970e8d2817fc2bc32078fb56e45f38ded4 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 14 Feb 2025 18:48:33 +0100 Subject: [PATCH 108/143] Update notes --- CLR-Host-Notes.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CLR-Host-Notes.md b/CLR-Host-Notes.md index 82ce3917bb6..f1db14ed2e0 100644 --- a/CLR-Host-Notes.md +++ b/CLR-Host-Notes.md @@ -42,8 +42,10 @@ Being part of the contract, the target platform could implement process terminat ### Trimmer issue (as of 14.02.2025) +https://github.com/dotnet/runtime/issues/112559 + It appears the trimmer removes a bit too much at this point. In order to make the application run with trimming, one -needs to add the following to their .csproj (solution found by Ivan Povazan): +needs to add the following to their .csproj (solution provided by Ivan Povazan): ```xml From 9a3ad925e350646ceebc1213c6e15682aa19f701 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 14 Feb 2025 21:55:31 +0100 Subject: [PATCH 109/143] Post-merge fixups --- src/native/CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 02e477f3d68..b94ad11879f 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -226,14 +226,14 @@ if(IS_CLR_RUNTIME) set(XA_RUNTIME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/clr/include) macro(xa_add_include_directories TARGET) - target_include_directories( - ${TARGET} - PRIVATE - ${XA_RUNTIME_INCLUDE_DIR} - ${EXTERNAL_DIR} - ${CONSTEXPR_XXH3_DIR} - ${RUNTIME_INCLUDE_DIR} - ) + target_include_directories( + ${TARGET} + PRIVATE + ${XA_RUNTIME_INCLUDE_DIR} + ${EXTERNAL_DIR} + ${CONSTEXPR_XXH3_DIR} + ${RUNTIME_INCLUDE_DIR} + ) endmacro() else() include_directories(mono) From eff1edd60fba2323d0450cb0d5ee722322477df2 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 17 Feb 2025 20:46:30 +0100 Subject: [PATCH 110/143] Type map implementation for CLR --- .../Android.Runtime/RuntimeNativeMethods.cs | 3 + src/Mono.Android/Java.Interop/TypeManager.cs | 23 +- ...oft.Android.Sdk.AssemblyResolution.targets | 14 - ...appingReleaseNativeAssemblyGeneratorCLR.cs | 21 +- src/native/clr/host/CMakeLists.txt | 1 + .../clr/host/generate-pinvoke-tables.cc | 1 + src/native/clr/host/host-jni.cc | 2 +- src/native/clr/host/host.cc | 14 +- src/native/clr/host/internal-pinvokes.cc | 7 +- src/native/clr/host/pinvoke-tables.include | 8 +- src/native/clr/host/typemap.cc | 291 ++++++++++++++++++ src/native/clr/include/host/typemap.hh | 24 +- .../include/runtime-base/internal-pinvokes.hh | 1 + .../include/runtime-base/timing-internal.hh | 7 +- src/native/clr/include/xamarin-app.hh | 1 + .../clr/runtime-base/timing-internal.cc | 4 +- 16 files changed, 381 insertions(+), 41 deletions(-) create mode 100644 src/native/clr/host/typemap.cc diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index c80a5dd1a09..360ae0ed722 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -92,6 +92,9 @@ internal static class RuntimeNativeMethods [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr clr_typemap_managed_to_java (string fullName, IntPtr mvid); + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern string clr_typemap_java_to_managed (string fullName); + [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index f2e9a4bae7a..97b772fe013 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -224,9 +224,30 @@ static Exception CreateJavaLocationException () [MethodImplAttribute(MethodImplOptions.InternalCall)] static extern Type monodroid_typemap_java_to_managed (string java_type_name); + static Type monovm_typemap_java_to_managed (string java_type_name) + { + return monodroid_typemap_java_to_managed (java_type_name); + } + + [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Value of java_type_name isn't statically known.")] + static Type? clr_typemap_java_to_managed (string java_type_name) + { + string? managedTypeName = RuntimeNativeMethods.clr_typemap_java_to_managed (java_type_name); + if (String.IsNullOrEmpty (managedTypeName)) { + return null; + } + + return Type.GetType (managedTypeName); + } + internal static Type? GetJavaToManagedType (string class_name) { - Type? type = monodroid_typemap_java_to_managed (class_name); + Type? type = JNIEnvInit.RuntimeType switch { + DotNetRuntimeType.MonoVM => monovm_typemap_java_to_managed (class_name), + DotNetRuntimeType.CoreCLR => clr_typemap_java_to_managed (class_name), + _ => throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported") + }; + if (type != null) return type; diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index 9dbd4ca4912..dfd733b4fb5 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 @@ -66,20 +66,6 @@ _ResolveAssemblies MSBuild target. - - - - - - diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs index 9c43c8e660e..c8c760b626d 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs @@ -231,6 +231,19 @@ public TypeMappingReleaseNativeAssemblyGeneratorCLR (TaskLoggingHelper log, Nati this.mappingData = mappingData ?? throw new ArgumentNullException (nameof (mappingData)); javaNameHash32Comparer = new JavaNameHash32Comparer (); javaNameHash64Comparer = new JavaNameHash64Comparer (); + + // Unfortunate, but we have to fix this up before proceeding + foreach (TypeMapGenerator.ModuleReleaseData module in mappingData.Modules) { + foreach (TypeMapGenerator.TypeMapReleaseEntry entry in module.Types) { + if (entry.ManagedTypeName.IndexOf ('/') < 0) { + continue; + } + + // CoreCLR will request for subtypes with the `+` level separator instead of + // the `/` one. + entry.ManagedTypeName = entry.ManagedTypeName.Replace ('/', '+'); + } + } } protected override void Construct (LlvmIrModule module) @@ -384,7 +397,9 @@ void InitJavaMap (ConstructionState cs) TypeMapJava map_entry; foreach (TypeMapGenerator.TypeMapReleaseEntry entry in mappingData.JavaTypes) { - uint managedTypeNameIndex = GetEntryIndex (entry.ManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); + string assemblyName = mappingData.Modules[entry.ModuleIndex].AssemblyName; + string fullManagedTypeName = $"{assemblyName}, {entry.ManagedTypeName}"; + uint managedTypeNameIndex = GetEntryIndex (fullManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); cs.JavaNames.Add (entry.JavaName); map_entry = new TypeMapJava { @@ -489,10 +504,10 @@ void HashJavaNames (ConstructionState cs) TypeMapJava entry = cs.JavaMap[i].Instance; // The cast is safe, xxHash will return a 32-bit value which (for convenience) was upcast to 64-bit - entry.JavaNameHash32 = (uint)TypeMapHelper.HashJavaName (entry.JavaName, is64Bit: false); + entry.JavaNameHash32 = (uint)TypeMapHelper.HashJavaNameForCLR (entry.JavaName, is64Bit: false); hashes32.Add (entry.JavaNameHash32); - entry.JavaNameHash64 = TypeMapHelper.HashJavaName (entry.JavaName, is64Bit: true); + entry.JavaNameHash64 = TypeMapHelper.HashJavaNameForCLR (entry.JavaName, is64Bit: true); hashes64.Add (entry.JavaNameHash64); } } diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index e011c0ff124..5e1c6098da6 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -35,6 +35,7 @@ set(XAMARIN_MONODROID_SOURCES internal-pinvokes.cc os-bridge.cc pinvoke-override.cc + typemap.cc ) list(APPEND LOCAL_CLANG_CHECK_SOURCES diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index cd6da7be976..e3b3c98bbe6 100644 --- a/src/native/clr/host/generate-pinvoke-tables.cc +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -71,6 +71,7 @@ const std::vector internal_pinvoke_names = { // "monodroid_timing_stop", "monodroid_TypeManager_get_java_class_name", "clr_typemap_managed_to_java", + "clr_typemap_java_to_managed", // "_monodroid_weak_gref_delete", // "_monodroid_weak_gref_get", // "_monodroid_weak_gref_new", diff --git a/src/native/clr/host/host-jni.cc b/src/native/clr/host/host-jni.cc index 21dc862d5cf..1b72015fc24 100644 --- a/src/native/clr/host/host-jni.cc +++ b/src/native/clr/host/host-jni.cc @@ -19,7 +19,7 @@ JNICALL Java_mono_android_Runtime_dumpTimingData ([[maybe_unused]] JNIEnv *env, // return; // } - // internal_timing->dump (); + // internal_timing.dump (); } JNIEXPORT void diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 2b7a4f97285..59f7fe03f00 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -167,7 +167,7 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl size_t total_time_index; if (FastTiming::enabled ()) [[unlikely]] { _timing = std::make_unique (); - total_time_index = internal_timing->start_event (TimingEventKind::TotalRuntimeInit); + total_time_index = internal_timing.start_event (TimingEventKind::TotalRuntimeInit); } jstring_array_wrapper applicationDirs (env, appDirs); @@ -257,7 +257,7 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl size_t native_to_managed_index; if (FastTiming::enabled ()) [[unlikely]] { - native_to_managed_index = internal_timing->start_event (TimingEventKind::NativeToManagedTransition); + native_to_managed_index = internal_timing.start_event (TimingEventKind::NativeToManagedTransition); } void *delegate = nullptr; @@ -291,11 +291,11 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl initialize (&init); if (FastTiming::enabled ()) [[unlikely]] { - internal_timing->end_event (native_to_managed_index); + internal_timing.end_event (native_to_managed_index); } if (FastTiming::enabled ()) [[unlikely]] { - internal_timing->end_event (total_time_index); + internal_timing.end_event (total_time_index); } } @@ -303,7 +303,7 @@ void Host::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, { size_t total_time_index; if (FastTiming::enabled ()) [[unlikely]] { - total_time_index = internal_timing->start_event (TimingEventKind::RuntimeRegister); + total_time_index = internal_timing.start_event (TimingEventKind::RuntimeRegister); } jsize managedType_len = env->GetStringLength (managedType); @@ -318,14 +318,14 @@ void Host::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, env->ReleaseStringChars (managedType, managedType_ptr); if (FastTiming::enabled ()) [[unlikely]] { - internal_timing->end_event (total_time_index, true /* uses_more_info */); + internal_timing.end_event (total_time_index, true /* uses_more_info */); dynamic_local_string type; const char *mt_ptr = env->GetStringUTFChars (managedType, nullptr); type.assign (mt_ptr, strlen (mt_ptr)); env->ReleaseStringUTFChars (managedType, mt_ptr); - internal_timing->add_more_info (total_time_index, type); + internal_timing.add_more_info (total_time_index, type); } } diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index be2ab2185d7..4f34ebd2d98 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -25,7 +25,12 @@ void _monodroid_gref_log_delete (jobject handle, char type, const char *threadNa const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept { - return TypeMap::typemap_managed_to_java (typeName, mvid); + return TypeMapper::typemap_managed_to_java (typeName, mvid); +} + +const char* clr_typemap_java_to_managed (const char *typeName) noexcept +{ + return TypeMapper::typemap_java_to_managed (typeName); } void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include index 491bb5ee7e6..c7f33d66265 100644 --- a/src/native/clr/host/pinvoke-tables.include +++ b/src/native/clr/host/pinvoke-tables.include @@ -11,9 +11,10 @@ namespace { #if INTPTR_MAX == INT64_MAX //64-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ {0x4b1956138764939a, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, {0x9187e6bc6294cacf, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, + {0x9a946dfe9916a942, "clr_typemap_java_to_managed", reinterpret_cast(&clr_typemap_java_to_managed)}, {0xa7f58f3ee428cc6b, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, {0xae3df96dda0143bd, "_monodroid_gref_log", reinterpret_cast(&_monodroid_gref_log)}, {0xb8306f71b963cd3d, "monodroid_log", reinterpret_cast(&monodroid_log)}, @@ -512,11 +513,12 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x18 constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; #else //32-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ {0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast(&monodroid_TypeManager_get_java_class_name)}, {0x656e00bd, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, {0xa04e5d1c, "monodroid_free", reinterpret_cast(&monodroid_free)}, {0xb02468aa, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, + {0xb6431f9a, "clr_typemap_java_to_managed", reinterpret_cast(&clr_typemap_java_to_managed)}, {0xbe8d7701, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, {0xc5146c54, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, {0xe7e77ca5, "_monodroid_gref_log", reinterpret_cast(&_monodroid_gref_log)}, @@ -1013,6 +1015,6 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93 constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a; #endif -constexpr size_t internal_pinvokes_count = 8; +constexpr size_t internal_pinvokes_count = 9; constexpr size_t dotnet_pinvokes_count = 477; } // end of anonymous namespace diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc new file mode 100644 index 00000000000..f71748e35ea --- /dev/null +++ b/src/native/clr/host/typemap.cc @@ -0,0 +1,291 @@ +#include + +#include +#include +#include +#include +#include + +using namespace xamarin::android; + +namespace { + class MonoGuidString + { + static inline constexpr size_t MVID_SIZE = 16; + static inline constexpr size_t NUM_HYPHENS = 4; + static inline constexpr size_t BUF_SIZE = (MVID_SIZE * 2) + NUM_HYPHENS + 1; + static inline std::array hex_map { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + }; + + public: + explicit MonoGuidString (const uint8_t *mvid) noexcept + { + if (mvid == nullptr) { + _ascii_form[0] = '\0'; + return; + } + + // In the caller we trust, we have no way to validate the size here + auto to_hex = [this, &mvid] (size_t &dest_idx, size_t src_idx) { + _ascii_form[dest_idx++] = hex_map[(mvid[src_idx] & 0xf0) >> 4]; + _ascii_form[dest_idx++] = hex_map[mvid[src_idx] & 0x0f]; + }; + + auto hyphen = [this] (size_t &dest_idx) { + _ascii_form[dest_idx++] = '-'; + }; + + size_t dest_idx = 0; + to_hex (dest_idx, 3); to_hex (dest_idx, 2); to_hex (dest_idx, 1); to_hex (dest_idx, 0); + hyphen (dest_idx); + + to_hex (dest_idx, 5); to_hex (dest_idx, 4); + hyphen (dest_idx); + + to_hex (dest_idx, 7); to_hex (dest_idx, 6); + hyphen (dest_idx); + + to_hex (dest_idx, 8); to_hex (dest_idx, 9); + hyphen (dest_idx); + + to_hex (dest_idx, 10); to_hex (dest_idx, 11); to_hex (dest_idx, 12); + to_hex (dest_idx, 13); to_hex (dest_idx, 14); to_hex (dest_idx, 15); + + _ascii_form[_ascii_form.size () - 1] = '\0'; + } + + auto c_str () const noexcept -> const char* + { + return _ascii_form.data (); + } + + private: + std::array _ascii_form; + }; +} + +#if defined(DEBUG) +[[gnu::always_inline]] +auto TypeMapper::typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char* +{ + Helpers::abort_application ("TypeMap support for Debug builds not implemented yet"sv); +} +#endif // def DEBUG + +#if defined(RELEASE) +[[gnu::always_inline]] +auto TypeMapper::compare_mvid (const uint8_t *mvid, TypeMapModule const& module) noexcept -> int +{ + return memcmp (module.module_uuid, mvid, sizeof(module.module_uuid)); +} + +[[gnu::always_inline]] +auto TypeMapper::find_module_entry (const uint8_t *mvid, const TypeMapModule *entries, size_t entry_count) noexcept -> const TypeMapModule* +{ + if (entries == nullptr || mvid == nullptr) [[unlikely]] { + return nullptr; + } + + auto equal = [](TypeMapModule const& entry, const uint8_t *key) -> bool { return compare_mvid (key, entry) == 0; }; + auto less_than = [](TypeMapModule const& entry, const uint8_t *key) -> bool { return compare_mvid (key, entry) < 0; }; + ssize_t idx = Search::binary_search (mvid, entries, entry_count); + if (idx >= 0) [[likely]] { + return &entries[idx]; + } + + return nullptr; +} + +[[gnu::always_inline]] +auto TypeMapper::find_managed_to_java_map_entry (hash_t name_hash, const TypeMapModuleEntry *map, size_t entry_count) noexcept -> const TypeMapModuleEntry* +{ + if (map == nullptr) { + return nullptr; + }; + + auto equal = [](TypeMapModuleEntry const& entry, hash_t key) -> bool { return entry.managed_type_name_hash == key; }; + auto less_than = [](TypeMapModuleEntry const& entry, hash_t key) -> bool { return entry.managed_type_name_hash < key; }; + ssize_t idx = Search::binary_search (name_hash, map, entry_count); + if (idx >= 0) [[likely]] { + return &map[idx]; + } + + return nullptr; +} + +[[gnu::always_inline]] +auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char* +{ + const TypeMapModule *match = find_module_entry (mvid, managed_to_java_map, managed_to_java_map_module_count); + if (match == nullptr) { + if (mvid == nullptr) { + log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); + } else { + log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found."sv, MonoGuidString (mvid).c_str ()); + } + return nullptr; + } + + log_debug (LOG_ASSEMBLY, "typemap: found module matching MVID [{}]"sv, MonoGuidString (mvid).c_str ()); + hash_t name_hash = xxhash::hash (typeName, strlen (typeName)); + + const TypeMapModuleEntry *entry = find_managed_to_java_map_entry (name_hash, match->map, match->entry_count); + if (entry == nullptr) [[unlikely]] { + if (match->map == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).c_str ()); + return nullptr; + } + + if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { + log_debug ( + LOG_ASSEMBLY, + "typemap: searching module [{}] duplicate map for type '{}' (hash {:x})", + MonoGuidString (mvid).c_str (), + optional_string (typeName), + name_hash + ); + entry = find_managed_to_java_map_entry (name_hash, match->duplicate_map, match->duplicate_count); + } + + if (entry == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) not found in module [{}] ({}).", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]) + ); + return nullptr; + } + } + + if (entry->java_map_index >= java_type_count) [[unlikely]] { + log_warn ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) has invalid Java type index {}", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]), + entry->java_map_index + ); + return nullptr; + } + + TypeMapJava const& java_entry = java_to_managed_map[entry->java_map_index]; + if (java_entry.java_name_index >= java_type_count) [[unlikely]] { + log_warn ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]), + entry->java_map_index, + java_entry.java_name_index + ); + + return nullptr; + } + + const char *ret = java_type_names[java_entry.java_name_index]; + if (ret == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}", entry->java_map_index); + } + + log_debug ( + LOG_ASSEMBLY, + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) corresponds to Java type '{}'", + optional_string (typeName), + name_hash, + MonoGuidString (mvid).c_str (), + optional_string (managed_assembly_names[match->assembly_name_index]), + ret + ); + + return ret; +} +#endif // def RELEASE + +[[gnu::flatten]] +auto TypeMapper::typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char* +{ + size_t total_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + //timing = new Timing (); + total_time_index = internal_timing.start_event (TimingEventKind::ManagedToJava); + } + + if (typeName == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_managed_to_java"); + return nullptr; + } + + const char *ret = nullptr; +#if defined(RELEASE) + ret = typemap_managed_to_java_release (typeName, mvid); +#else + ret = typemap_managed_to_java_debug (typeName, mvid); +#endif + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.end_event (total_time_index); + } + + return ret; +} + +#if defined(DEBUG) +[[gnu::flatten]] +auto TypeMapper::typemap_java_to_managed (const char *typeName) noexcept -> const char* +{ + Helpers::abort_application ("typemap_java_to_managed not implemented for debug builds yet"); +} +#else // def DEBUG + +[[gnu::always_inline]] +auto TypeMapper::find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava* +{ + ssize_t idx = Search::binary_search (name_hash, java_to_managed_hashes, java_type_count); + if (idx < 0) [[unlikely]] { + return nullptr; + } + + return &java_to_managed_map[idx]; +} + +[[gnu::flatten]] +auto TypeMapper::typemap_java_to_managed (const char *typeName) noexcept -> const char* +{ + log_warn (LOG_ASSEMBLY, "{} WIP"sv, __PRETTY_FUNCTION__); + log_warn (LOG_ASSEMBLY, " asking for '{}'"sv, optional_string (typeName)); + + if (typeName == nullptr) [[unlikely]] { + return nullptr; + } + + hash_t name_hash = xxhash::hash (typeName, strlen (typeName)); + TypeMapJava const* java_entry = find_java_to_managed_entry (name_hash); + if (java_entry == nullptr) { + log_info ( + LOG_ASSEMBLY, + "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", + optional_string (typeName), + name_hash + ); + + return nullptr; + } + + log_debug ( + LOG_ASSEMBLY, + "Java type '{}' corresponds to managed type '{}'", + optional_string (typeName), + optional_string (managed_type_names[java_entry->managed_type_name_index]) + ); + return managed_type_names[java_entry->managed_type_name_index]; +} +#endif // ndef DEBUG diff --git a/src/native/clr/include/host/typemap.hh b/src/native/clr/include/host/typemap.hh index 518e5f333d4..5e535bde732 100644 --- a/src/native/clr/include/host/typemap.hh +++ b/src/native/clr/include/host/typemap.hh @@ -1,18 +1,28 @@ #pragma once #include + #include "../runtime-base/logger.hh" +#include +#include "../xamarin-app.hh" namespace xamarin::android { - class TypeMap + class TypeMapper { public: - static auto typemap_managed_to_java ([[maybe_unused]] const char *typeName, [[maybe_unused]] const uint8_t *mvid) noexcept -> const char* - { - log_warn (LOG_ASSEMBLY, "{} not implemented yet", __PRETTY_FUNCTION__); - log_warn (LOG_ASSEMBLY, " asked for '{}'", optional_string (typeName)); + static auto typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char*; + static auto typemap_java_to_managed (const char *typeName) noexcept -> const char*; + + private: +#if defined(RELEASE) + static auto compare_mvid (const uint8_t *mvid, TypeMapModule const& module) noexcept -> int; + static auto find_module_entry (const uint8_t *mvid, const TypeMapModule *entries, size_t entry_count) noexcept -> const TypeMapModule*; + static auto find_managed_to_java_map_entry (hash_t name_hash, const TypeMapModuleEntry *map, size_t entry_count) noexcept -> const TypeMapModuleEntry*; + static auto typemap_managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char*; - return nullptr; - } + static auto find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava*; +#else + static auto typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char*; +#endif }; } diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index f2aa3792369..b2c162ecd85 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -9,6 +9,7 @@ void _monodroid_gref_log (const char *message) noexcept; int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept; void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept; +const char* clr_typemap_java_to_managed (const char *typeName) noexcept; void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; void monodroid_free (void *ptr) noexcept; diff --git a/src/native/clr/include/runtime-base/timing-internal.hh b/src/native/clr/include/runtime-base/timing-internal.hh index 6897c34df1d..185f786bff7 100644 --- a/src/native/clr/include/runtime-base/timing-internal.hh +++ b/src/native/clr/include/runtime-base/timing-internal.hh @@ -88,12 +88,15 @@ namespace xamarin::android { static constexpr uint32_t ns_in_second = ms_in_second * ns_in_millisecond; protected: - FastTiming () noexcept + void configure_for_use () noexcept { events.reserve (INITIAL_EVENT_VECTOR_SIZE); } public: + constexpr FastTiming () noexcept + {} + [[gnu::always_inline]] static auto enabled () noexcept -> bool { @@ -462,5 +465,5 @@ namespace xamarin::android { static inline bool immediate_logging = false; }; - extern FastTiming *internal_timing; + extern FastTiming internal_timing; } diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index be8c30541e0..55270d408c6 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -1,6 +1,7 @@ // Dear Emacs, this is a -*- C++ -*- header #pragma once +#include #include #include diff --git a/src/native/clr/runtime-base/timing-internal.cc b/src/native/clr/runtime-base/timing-internal.cc index fab5e4ed160..8df98638427 100644 --- a/src/native/clr/runtime-base/timing-internal.cc +++ b/src/native/clr/runtime-base/timing-internal.cc @@ -4,13 +4,13 @@ using namespace xamarin::android; namespace xamarin::android { - FastTiming *internal_timing = nullptr; + FastTiming internal_timing; } void FastTiming::really_initialize (bool log_immediately) noexcept { - internal_timing = new FastTiming (); + internal_timing.configure_for_use (); is_enabled = true; immediate_logging = log_immediately; From f45e45a77a8746d3872875a0b62731f40367e704 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 18 Feb 2025 16:39:18 +0100 Subject: [PATCH 111/143] MAUI hello world works now --- .../Android.Runtime/RuntimeNativeMethods.cs | 2 +- src/Mono.Android/Java.Interop/TypeManager.cs | 10 +++++++--- .../TypeMappingReleaseNativeAssemblyGeneratorCLR.cs | 2 +- src/native/clr/host/generate-pinvoke-tables.cc | 4 ++++ src/native/clr/host/pinvoke-override.cc | 2 +- src/native/clr/host/pinvoke-tables.include | 10 +++++++--- src/native/clr/host/typemap.cc | 5 +++-- 7 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index 360ae0ed722..8965d50b114 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -93,7 +93,7 @@ internal static class RuntimeNativeMethods internal static extern IntPtr clr_typemap_managed_to_java (string fullName, IntPtr mvid); [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern string clr_typemap_java_to_managed (string fullName); + internal static extern IntPtr clr_typemap_java_to_managed (string fullName); [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index 97b772fe013..a8744e5f0f1 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -232,12 +232,16 @@ static Type monovm_typemap_java_to_managed (string java_type_name) [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Value of java_type_name isn't statically known.")] static Type? clr_typemap_java_to_managed (string java_type_name) { - string? managedTypeName = RuntimeNativeMethods.clr_typemap_java_to_managed (java_type_name); - if (String.IsNullOrEmpty (managedTypeName)) { + IntPtr managedTypeNamePointer = RuntimeNativeMethods.clr_typemap_java_to_managed (java_type_name); + if (managedTypeNamePointer == IntPtr.Zero) { return null; } - return Type.GetType (managedTypeName); + string managedTypeName = Marshal.PtrToStringAnsi (managedTypeNamePointer); + Logger.Log (LogLevel.Info, "monodroid", $"clr_typemap_java_to_managed ('{java_type_name}') returned '{managedTypeName}'"); + Type ret = Type.GetType (managedTypeName); + Logger.Log (LogLevel.Info, "monodroid", $"Loaded type: {ret}"); + return ret; } internal static Type? GetJavaToManagedType (string class_name) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs index c8c760b626d..d2871c1e245 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs @@ -398,7 +398,7 @@ void InitJavaMap (ConstructionState cs) TypeMapJava map_entry; foreach (TypeMapGenerator.TypeMapReleaseEntry entry in mappingData.JavaTypes) { string assemblyName = mappingData.Modules[entry.ModuleIndex].AssemblyName; - string fullManagedTypeName = $"{assemblyName}, {entry.ManagedTypeName}"; + string fullManagedTypeName = $"{entry.ManagedTypeName}, {assemblyName}"; uint managedTypeNameIndex = GetEntryIndex (fullManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); cs.JavaNames.Add (entry.JavaName); diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index e3b3c98bbe6..e2055f45763 100644 --- a/src/native/clr/host/generate-pinvoke-tables.cc +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -79,6 +79,9 @@ const std::vector internal_pinvoke_names = { // "recv_uninterrupted", // "send_uninterrupted", // "set_world_accessable", + +// We can treat liblog as "internal", since we link against it + "__android_log_print", }; const std::vector dotnet_pinvoke_names = { @@ -647,6 +650,7 @@ void write_library_name_hashes (Hash (*hasher)(const char*, size_t), std::ostrea { write_library_name_hash (hasher, output, "java-interop", "java_interop"); write_library_name_hash (hasher, output, "xa-internal-api", "xa_internal_api"); + write_library_name_hash (hasher, output, "liblog", "android_liblog"); write_library_name_hash (hasher, output, "libSystem.Native", "system_native"); write_library_name_hash (hasher, output, "libSystem.IO.Compression.Native", "system_io_compression_native"); write_library_name_hash (hasher, output, "libSystem.Security.Cryptography.Native.Android", "system_security_cryptography_native_android"); diff --git a/src/native/clr/host/pinvoke-override.cc b/src/native/clr/host/pinvoke-override.cc index a2edc9ef9b2..562bf7e3f7c 100644 --- a/src/native/clr/host/pinvoke-override.cc +++ b/src/native/clr/host/pinvoke-override.cc @@ -16,7 +16,7 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons hash_t library_name_hash = xxhash::hash (library_name, strlen (library_name)); hash_t entrypoint_hash = xxhash::hash (entrypoint_name, strlen (entrypoint_name)); - if (library_name_hash == java_interop_library_hash || library_name_hash == xa_internal_api_library_hash) { + if (library_name_hash == java_interop_library_hash || library_name_hash == xa_internal_api_library_hash || library_name_hash == android_liblog_library_hash) { PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include index c7f33d66265..73d07f125c6 100644 --- a/src/native/clr/host/pinvoke-tables.include +++ b/src/native/clr/host/pinvoke-tables.include @@ -11,7 +11,8 @@ namespace { #if INTPTR_MAX == INT64_MAX //64-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ + {0x4310c1531ddddc14, "__android_log_print", reinterpret_cast(&__android_log_print)}, {0x4b1956138764939a, "_monodroid_gref_log_new", reinterpret_cast(&_monodroid_gref_log_new)}, {0x9187e6bc6294cacf, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, {0x9a946dfe9916a942, "clr_typemap_java_to_managed", reinterpret_cast(&clr_typemap_java_to_managed)}, @@ -507,14 +508,16 @@ namespace { constexpr hash_t java_interop_library_hash = 0x54568ec36068e6b6; constexpr hash_t xa_internal_api_library_hash = 0x43fd1b21148361b2; +constexpr hash_t android_liblog_library_hash = 0x1f2e4bce0544fb0a; constexpr hash_t system_native_library_hash = 0x4cd7bd0032e920e1; constexpr hash_t system_io_compression_native_library_hash = 0x9190f4cb761b1d3c; constexpr hash_t system_security_cryptography_native_android_library_hash = 0x1848c0093f0afd8; constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; #else //32-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ {0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast(&monodroid_TypeManager_get_java_class_name)}, + {0x39e5b5d4, "__android_log_print", reinterpret_cast(&__android_log_print)}, {0x656e00bd, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, {0xa04e5d1c, "monodroid_free", reinterpret_cast(&monodroid_free)}, {0xb02468aa, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, @@ -1009,12 +1012,13 @@ constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; constexpr hash_t java_interop_library_hash = 0x6e36e350; constexpr hash_t xa_internal_api_library_hash = 0x13c9bd62; +constexpr hash_t android_liblog_library_hash = 0xa70c9969; constexpr hash_t system_native_library_hash = 0x5b9ade60; constexpr hash_t system_io_compression_native_library_hash = 0xafe3142c; constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93625cd; constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a; #endif -constexpr size_t internal_pinvokes_count = 9; +constexpr size_t internal_pinvokes_count = 10; constexpr size_t dotnet_pinvokes_count = 477; } // end of anonymous namespace diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index f71748e35ea..9d9d463db85 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -282,9 +282,10 @@ auto TypeMapper::typemap_java_to_managed (const char *typeName) noexcept -> cons log_debug ( LOG_ASSEMBLY, - "Java type '{}' corresponds to managed type '{}'", + "Java type '{}' corresponds to managed type '{}' ({:p}", optional_string (typeName), - optional_string (managed_type_names[java_entry->managed_type_name_index]) + optional_string (managed_type_names[java_entry->managed_type_name_index]), + reinterpret_cast(managed_type_names[java_entry->managed_type_name_index]) ); return managed_type_names[java_entry->managed_type_name_index]; } From d059b3e6797e4412083a64f3041b01accb885815 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 18 Feb 2025 21:32:35 -0500 Subject: [PATCH 112/143] Fix Windows build? By convention (and often enforced requirement), `$(OutputPath)` ends with `\`, which means that quoting it for use with ``: will often result in an *invalid* command, because the `\` escapes the quote! whatever "C:\path\to\output\" # ruh roh! The fix is to instead use `$(OutputPath.OutputPath.TrimEnd('\')`, which ensures that the path does *not* end in `\`, preventing the unintentional escape usage: whatever "C:\path\to\output" # yay! --- src/native/native-mono.csproj | 2 +- src/native/native.targets | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/native-mono.csproj b/src/native/native-mono.csproj index 518fd728712..5800dd911d1 100644 --- a/src/native/native-mono.csproj +++ b/src/native/native-mono.csproj @@ -11,7 +11,7 @@ - $(NativeRuntimeOutputRootDir)mono + $(NativeRuntimeOutputRootDir)mono\ MonoVM diff --git a/src/native/native.targets b/src/native/native.targets index 15b6afbfacd..4df76b789d3 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -90,7 +90,7 @@ <_ConfigureArchiveDSOStubCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - -DOUTPUT_PATH="$(OutputPath)" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" + -DOUTPUT_PATH="$(OutputPath.TrimEnd('\')" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub @@ -113,7 +113,7 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath)" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\')" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" From 5b7911383ab1c683579102fe65ec5fa37b2a28e1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 19 Feb 2025 09:43:24 +0100 Subject: [PATCH 113/143] Add missing parentheses --- src/native/native.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/native.targets b/src/native/native.targets index 4df76b789d3..6b997259f4a 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -90,7 +90,7 @@ <_ConfigureArchiveDSOStubCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - -DOUTPUT_PATH="$(OutputPath.TrimEnd('\')" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" + -DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) -DBUILD_ARCHIVE_DSO_STUB=ON -DSTRIP_DEBUG=ON "$(MSBuildThisFileDirectory)" $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-archive-dso-stub @@ -113,7 +113,7 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\')" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" From 235440bf56d382c636d8cce865e1c012016344b0 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 19 Feb 2025 10:57:18 +0100 Subject: [PATCH 114/143] Some cleanup --- src/Mono.Android/Android.Runtime/JNIEnv.cs | 1 - .../java/mono/android/clr/MonoPackageManager.java | 7 ------- src/native/clr/host/assembly-store.cc | 2 +- src/native/clr/host/host.cc | 4 ++-- src/native/clr/host/pinvoke-override.cc | 12 +++++++++++- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 6056c6ecc8d..abea8497918 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -451,7 +451,6 @@ static unsafe IntPtr monovm_typemap_managed_to_java (Type type, byte* mvidptr) mvid_data = mvid_bytes; } - RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"Current runtime type: {JNIEnvInit.RuntimeType}"); IntPtr ret; fixed (byte* mvidptr = mvid_data) { ret = JNIEnvInit.RuntimeType switch { diff --git a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java index 48b1603483b..4cfa0ea2169 100644 --- a/src/java-runtime/java/mono/android/clr/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/clr/MonoPackageManager.java @@ -27,7 +27,6 @@ public class MonoPackageManager { public static void LoadApplication (Context context) { - Log.w ("XACLR", "MonoPackageManager.LoadApplication: start"); synchronized (lock) { android.content.pm.ApplicationInfo runtimePackage = context.getApplicationInfo (); String[] apks = null; @@ -44,7 +43,6 @@ public static void LoadApplication (Context context) ApplicationRegistration.Context = context; } if (!initialized) { - Log.w ("XACLR", "MonoPackageManager.LoadApplication: initializing"); android.content.IntentFilter timezoneChangedFilter = new android.content.IntentFilter ( android.content.Intent.ACTION_TIMEZONE_CHANGED ); @@ -71,10 +69,8 @@ public static void LoadApplication (Context context) String[] appDirs = new String[] {filesDir, cacheDir, dataDir}; boolean haveSplitApks = runtimePackage.splitSourceDirs != null && runtimePackage.splitSourceDirs.length > 0; - Log.w ("XACLR", "MonoPackageManager.LoadApplication: load monodroid"); System.loadLibrary("monodroid"); - Log.w ("XACLR", "MonoPackageManager.LoadApplication: call Runtime.initInternal"); Runtime.initInternal ( language, apks, @@ -87,10 +83,7 @@ public static void LoadApplication (Context context) haveSplitApks ); - Log.w ("XACLR", "MonoPackageManager.LoadApplication: call registerApplications"); ApplicationRegistration.registerApplications (); - - Log.w ("XACLR", "MonoPackageManager.LoadApplication: initialized"); initialized = true; } } diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc index 0e7c174b4c0..e5ee5edf897 100644 --- a/src/native/clr/host/assembly-store.cc +++ b/src/native/clr/host/assembly-store.cc @@ -135,7 +135,7 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) { - log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.data ()), name_hash); + log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash 0x{:x}) not found", optional_string (name.data ()), name_hash); return nullptr; } diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 59f7fe03f00..d9d81f58d24 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -22,13 +22,13 @@ void Host::clr_error_writer (const char *message) noexcept size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept { - log_info (LOG_DEFAULT, "clr_get_runtime_property (\"{}\"...)", key); + log_debug (LOG_DEFAULT, "clr_get_runtime_property (\"{}\"...)", key); return 0; } bool Host::clr_bundle_probe (const char *path, void **data_start, int64_t *size) noexcept { - log_info (LOG_DEFAULT, "clr_bundle_probe (\"{}\"...)", path); + log_debug (LOG_DEFAULT, "clr_bundle_probe (\"{}\"...)", path); if (data_start == nullptr || size == nullptr) { return false; // TODO: abort instead? } diff --git a/src/native/clr/host/pinvoke-override.cc b/src/native/clr/host/pinvoke-override.cc index 562bf7e3f7c..d1467e4eda1 100644 --- a/src/native/clr/host/pinvoke-override.cc +++ b/src/native/clr/host/pinvoke-override.cc @@ -81,6 +81,16 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons optional_string (entrypoint_name), optional_string (library_name) ); + + // This is temporary, to catch p/invokes we might be missing that are used in the default templates + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Missing pinvoke {}@{}", + optional_string (entrypoint_name), + optional_string (library_name) + ) + ); } return handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); @@ -88,7 +98,7 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept { - log_info (LOG_ASSEMBLY, "clr_pinvoke_override (\"{}\", \"{}\")", library_name, entry_point_name); + log_debug (LOG_ASSEMBLY, "clr_pinvoke_override (\"{}\", \"{}\")", library_name, entry_point_name); void *ret = PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); log_debug (LOG_DEFAULT, "p/invoke {}found", ret == nullptr ? "not"sv : ""sv); return ret; From 947a60857917b31f2c868ef7aed60fa01dfb62e1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 20 Feb 2025 21:36:26 +0100 Subject: [PATCH 115/143] Changes --- ...icationConfigNativeAssemblyGeneratorCLR.cs | 89 +++++++++---------- .../Xamarin.Android.Common.targets | 2 +- src/native/clr/host/host.cc | 44 ++++++--- src/native/clr/host/typemap.cc | 3 - src/native/clr/include/host/host.hh | 8 +- src/native/clr/include/xamarin-app.hh | 3 +- src/native/clr/runtime-base/android-system.cc | 4 +- .../xamarin-app-stub/application_dso_stub.cc | 26 ++---- 8 files changed, 87 insertions(+), 92 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index b528906e3ed..92440adfc42 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -12,6 +12,11 @@ namespace Xamarin.Android.Tasks; class ApplicationConfigNativeAssemblyGeneratorCLR : LlvmIrComposer { + // From host_runtime_contract.h in dotnet/runtime + const string HOST_PROPERTY_RUNTIME_CONTRACT = "HOST_RUNTIME_CONTRACT"; + const string HOST_PROPERTY_BUNDLE_PROBE = "BUNDLE_PROBE"; + const string HOST_PROPERTY_PINVOKE_OVERRIDE = "PINVOKE_OVERRIDE"; + sealed class DSOCacheEntryContextDataProvider : NativeAssemblerStructContextDataProvider { public override string GetComment (object data, string fieldName) @@ -127,26 +132,6 @@ sealed class RuntimePropertyIndexEntry public uint index; } - // Order of fields and their types must correspond **exactly** to those in CoreCLR's host_runtime_contract.h - sealed class host_configuration_property - { - [NativeAssembler (IsUTF16 = true)] - public string name; - - [NativeAssembler (IsUTF16 = true)] - public string value; - } - - // Order of fields and their types must correspond **exactly** to those in CoreCLR's host_runtime_contract.h - const string HostConfigurationPropertiesDataSymbol = "_host_configuration_properties_data"; - sealed class host_configuration_properties - { - public ulong nitems; - - [NativePointer (PointsToSymbol = HostConfigurationPropertiesDataSymbol)] - public host_configuration_property data; - } - sealed class XamarinAndroidBundledAssemblyContextDataProvider : NativeAssemblerStructContextDataProvider { public override ulong GetBufferSize (object data, string fieldName) @@ -197,8 +182,6 @@ sealed class XamarinAndroidBundledAssembly List>? xamarinAndroidBundledAssemblies; List>? runtimePropertiesData; List>? runtimePropertyIndex; - List> hostConfigurationPropertiesData; - StructureInstance hostConfigurationProperties; StructureInfo? applicationConfigStructureInfo; StructureInfo? dsoCacheEntryStructureInfo; @@ -240,7 +223,16 @@ public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary if (runtimeProperties != null) { this.runtimeProperties = new SortedDictionary (runtimeProperties, StringComparer.Ordinal); + } else { + this.runtimeProperties = new SortedDictionary (StringComparer.Ordinal); } + + // This will be filled in by the native host. + this.runtimeProperties[HOST_PROPERTY_RUNTIME_CONTRACT] = String.Empty; + + // these mustn't be there, they would break our host contract + this.runtimeProperties.Remove (HOST_PROPERTY_PINVOKE_OVERRIDE); + this.runtimeProperties.Remove (HOST_PROPERTY_BUNDLE_PROBE); } protected override void Construct (LlvmIrModule module) @@ -310,7 +302,7 @@ protected override void Construct (LlvmIrModule module) }; module.Add (bundled_assemblies); - (runtimePropertiesData, runtimePropertyIndex, hostConfigurationPropertiesData) = InitRuntimeProperties (); + (runtimePropertiesData, runtimePropertyIndex) = InitRuntimeProperties (); var runtime_properties = new LlvmIrGlobalVariable (runtimePropertiesData, "runtime_properties", LlvmIrVariableOptions.GlobalConstant) { Comment = "Runtime config properties", }; @@ -322,22 +314,33 @@ protected override void Construct (LlvmIrModule module) }; module.Add (runtime_property_index); - var _host_configuration_properties_data = new LlvmIrGlobalVariable (hostConfigurationPropertiesData, HostConfigurationPropertiesDataSymbol, LlvmIrVariableOptions.LocalConstant) { - Comment = "Runtime host configuration properties data, encoded using 16-bit Unicode, as expected by CoreCLR", + // HOST_PROPERTY_RUNTIME_CONTRACT will come first, our native runtime requires that since it needs + // to set its value in the values array and we don't want to spend time searching for the index, nor + // we want to add yet another variable storing the index to the entry. KISS. + var runtime_property_names = new List { + HOST_PROPERTY_RUNTIME_CONTRACT, + }; + var runtime_property_values = new List { + null, }; - module.Add (_host_configuration_properties_data); - var hostConfigProps = new host_configuration_properties { - nitems = (ulong)hostConfigurationPropertiesData.Count, + foreach (var kvp in runtimeProperties) { + if (String.Compare (kvp.Key, HOST_PROPERTY_RUNTIME_CONTRACT, StringComparison.Ordinal) == 0) { + continue; + } + runtime_property_names.Add (kvp.Key); + runtime_property_values.Add (kvp.Value); + } + + var init_runtime_property_names = new LlvmIrGlobalVariable (runtime_property_names, "init_runtime_property_names", LlvmIrVariableOptions.GlobalConstant) { + Comment = "Names of properties passed to coreclr_initialize", }; - var host_config_props = new LlvmIrGlobalVariable ( - new StructureInstance (hostConfigurationPropertiesStructureInfo, hostConfigProps), - "host_config_properties", - LlvmIrVariableOptions.GlobalConstant) - { - Comment = "Runtime host config properties, for CoreCLR initialization phase" + module.Add (init_runtime_property_names); + + var init_runtime_property_values = new LlvmIrGlobalVariable (runtime_property_values, "init_runtime_property_values", LlvmIrVariableOptions.GlobalWritable) { + Comment = "Values of properties passed to coreclr_initialize", }; - module.Add (host_config_props); + module.Add (init_runtime_property_values); AddAssemblyStores (module); } @@ -368,16 +371,14 @@ void HashAndSortRuntimePropertiesIndex (LlvmIrVariable variable, LlvmIrModuleTar ( List> runtimeProps, - List> runtimePropsIndex, - List> configProps + List> runtimePropsIndex ) InitRuntimeProperties () { var runtimeProps = new List> (); var runtimePropsIndex = new List> (); - var configProps = new List> (); if (runtimeProperties == null || runtimeProperties.Count == 0) { - return (runtimeProps, runtimePropsIndex, configProps); + return (runtimeProps, runtimePropsIndex); } foreach (var kvp in runtimeProperties) { @@ -398,15 +399,9 @@ List> configProps index = (uint)(runtimeProps.Count - 1), }; runtimePropsIndex.Add (new StructureInstance (runtimePropertyIndexEntryStructureInfo, indexEntry)); - - var hostConfigProperty = new host_configuration_property { - name = name, - value = value, - }; - configProps.Add (new StructureInstance (hostConfigurationPropertyStructureInfo, hostConfigProperty)); } - return (runtimeProps, runtimePropsIndex, configProps); + return (runtimeProps, runtimePropsIndex); } void AddAssemblyStores (LlvmIrModule module) @@ -542,7 +537,5 @@ void MapStructures (LlvmIrModule module) dsoApkEntryStructureInfo = module.MapStructure (); runtimePropertyStructureInfo = module.MapStructure (); runtimePropertyIndexEntryStructureInfo = module.MapStructure (); - hostConfigurationPropertyStructureInfo = module.MapStructure (); - hostConfigurationPropertiesStructureInfo = module.MapStructure (); } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 82c1156fe1a..2ae443e5d40 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2073,7 +2073,7 @@ because xbuild doesn't support framework reference assemblies. - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app.so"> %(_BuildTargetAbis.Identity) diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index d9d81f58d24..0c84fe8637e 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -1,3 +1,5 @@ +#include + #include #include @@ -26,7 +28,7 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size return 0; } -bool Host::clr_bundle_probe (const char *path, void **data_start, int64_t *size) noexcept +bool Host::clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept { log_debug (LOG_DEFAULT, "clr_bundle_probe (\"{}\"...)", path); if (data_start == nullptr || size == nullptr) { @@ -133,8 +135,10 @@ auto Host::create_delegate ( &delegate ); log_debug (LOG_ASSEMBLY, - "{} delegate creation result == {:x}; delegate == {:p}", - Constants::JNIENVINIT_FULL_TYPE_NAME, + "{}@{}.{} delegate creation result == {:x}; delegate == {:p}", + assembly_name, + type_name, + method_name, static_cast(hr), delegate ); @@ -191,17 +195,32 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl gather_assemblies_and_libraries (runtimeApks, haveSplitApks); - log_write (LOG_DEFAULT, LogLevel::Info, "Calling CoreCLR initialization routine"); + size_t clr_init_time_index; + if (FastTiming::enabled ()) [[unlikely]] { + clr_init_time_index = internal_timing.start_event (TimingEventKind::MonoRuntimeInit); + } + coreclr_set_error_writer (clr_error_writer); - int hr = android_coreclr_initialize ( + // We REALLY shouldn't be doing this + snprintf (host_contract_ptr_buffer.data (), host_contract_ptr_buffer.size (), "%p", &runtime_contract); + + // The first entry in the property arrays is for the host contract pointer. Application build makes sure + // of that. + init_runtime_property_values[0] = host_contract_ptr_buffer.data (); + int hr = coreclr_initialize ( application_config.android_package_name, - u"Xamarin.Android", - &runtime_contract, - &host_config_properties, + "Xamarin.Android", + (int)application_config.number_of_runtime_properties, + init_runtime_property_names, + const_cast(init_runtime_property_values), &clr_host, &domain_id ); - log_debug (LOG_ASSEMBLY, "CoreCLR init result == {:x}; clr_host == {:p}; domain ID == {}", static_cast(hr), clr_host, domain_id); + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.end_event (clr_init_time_index); + } + // TODO: make S_OK & friends known to us if (hr != 0 /* S_OK */) { Helpers::abort_application ( @@ -253,8 +272,6 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl OSBridge::initialize_on_runtime_init (env, runtimeClass); - log_debug (LOG_DEFAULT, "Calling into managed runtime init"sv); - size_t native_to_managed_index; if (FastTiming::enabled ()) [[unlikely]] { native_to_managed_index = internal_timing.start_event (TimingEventKind::NativeToManagedTransition); @@ -288,13 +305,12 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl ); } ); + + log_debug (LOG_DEFAULT, "Calling into managed runtime init"sv); initialize (&init); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.end_event (native_to_managed_index); - } - - if (FastTiming::enabled ()) [[unlikely]] { internal_timing.end_event (total_time_index); } } diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 9d9d463db85..7b7fa77e2ef 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -260,9 +260,6 @@ auto TypeMapper::find_java_to_managed_entry (hash_t name_hash) noexcept -> const [[gnu::flatten]] auto TypeMapper::typemap_java_to_managed (const char *typeName) noexcept -> const char* { - log_warn (LOG_ASSEMBLY, "{} WIP"sv, __PRETTY_FUNCTION__); - log_warn (LOG_ASSEMBLY, " asking for '{}'"sv, optional_string (typeName)); - if (typeName == nullptr) [[unlikely]] { return nullptr; } diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 9d66d8b720a..1e8f6517686 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -34,7 +35,7 @@ namespace xamarin::android { static void gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks); static size_t clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, void *contract_context) noexcept; - static bool clr_bundle_probe (const char *path, void **data_start, int64_t *size) noexcept; + static bool clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept; static const void* clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept; static void clr_error_writer (const char *message) noexcept; @@ -56,9 +57,12 @@ namespace xamarin::android { .size = sizeof(host_runtime_contract), .context = nullptr, .get_runtime_property = clr_get_runtime_property, - .android_bundle_probe = clr_bundle_probe, + .external_assembly_probe = clr_external_assembly_probe, .bundle_probe = nullptr, .pinvoke_override = clr_pinvoke_override, }; + + // Enough to fit 0xffffffffffffffff + terminating NUL + static inline std::array host_contract_ptr_buffer{}; }; } diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index 55270d408c6..f0004675f75 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -341,7 +341,8 @@ extern "C" { [[gnu::visibility("default")]] extern const RuntimeProperty runtime_properties[]; [[gnu::visibility("default")]] extern const RuntimePropertyIndexEntry runtime_property_index[]; - [[gnu::visibility("default")]] extern const host_configuration_properties host_config_properties; + [[gnu::visibility("default")]] extern const char *init_runtime_property_names[]; + [[gnu::visibility("default")]] extern char *init_runtime_property_values[]; } // diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index cd3a15d4495..2915b0fbcdc 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -241,9 +241,9 @@ AndroidSystem::setup_environment () noexcept var_value = ""; } - if constexpr (Constants::is_debug_build) { +// if constexpr (Constants::is_debug_build) { log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); - } +// } if (setenv (var_name, var_value, 1) < 0) { log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 38bad32f5e5..34ee15f4c66 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -340,26 +340,10 @@ const RuntimePropertyIndexEntry runtime_property_index[] = { }, }; -namespace { - const host_configuration_property _host_configuration_properties_data[] = { - { - .name = u"test_string", - .value = u"string value", - }, - - { - .name = u"test_integer", - .value = u"23", - }, - - { - .name = u"test_boolean", - .value = u"true", - }, - }; -} +const char *init_runtime_property_names[] = { + "HOST_RUNTIME_CONTRACT", +}; -const host_configuration_properties host_config_properties = { - .nitems = 3, - .data = _host_configuration_properties_data, +char *init_runtime_property_values[] { + nullptr, }; From 23c3d39e71f1856d2571202efd94a51817b3797e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 21 Feb 2025 09:31:27 +0100 Subject: [PATCH 116/143] Fix after rebase --- Xamarin.Android.sln | 7 + .../targets/Microsoft.Android.Sdk.targets | 3 +- .../WorkloadManifest.in.json | 4 +- .../Tasks/CollectAssemblyFilesForArchive.cs | 15 +-- .../Tasks/GenerateJavaStubs.cs | 33 ++++- .../Tasks/WrapAssembliesAsSharedLibraries.cs | 5 +- .../BuildReleaseArm64SimpleDotNet.apkdesc | 26 ++-- .../BuildReleaseArm64XFormsDotNet.apkdesc | 70 +++++----- .../Utilities/ManifestDocument.cs | 2 +- .../Xamarin.Android.Common.targets | 6 +- src/native/CMakeLists.txt | 10 +- src/native/common/include/shared/log_level.hh | 126 +++--------------- .../mono/monodroid/internal-pinvokes.cc | 7 - src/native/mono/shared/cpp-util.hh | 2 +- 14 files changed, 125 insertions(+), 191 deletions(-) diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index faccbca0dbd..c24d1c97d51 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -127,6 +127,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proguard-android", "src\pro EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "native-clr", "src\native\native-clr.csproj", "{39F49484-872A-489D-8E6B-3BC532DD571D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Runtime.NativeAOT", "src\Microsoft.Android.Runtime.NativeAOT\Microsoft.Android.Runtime.NativeAOT.csproj", "{E8831F32-11D7-D42C-E43C-711998BC357A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|AnyCPU = Debug|AnyCPU @@ -353,6 +355,10 @@ Global {39F49484-872A-489D-8E6B-3BC532DD571D}.Debug|AnyCPU.Build.0 = Debug|Any CPU {39F49484-872A-489D-8E6B-3BC532DD571D}.Release|AnyCPU.ActiveCfg = Release|Any CPU {39F49484-872A-489D-8E6B-3BC532DD571D}.Release|AnyCPU.Build.0 = Release|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.Build.0 = Debug|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Release|AnyCPU.ActiveCfg = Release|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Release|AnyCPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -413,6 +419,7 @@ Global {5E806C9F-1B67-4B6B-A6AB-258834250DBB} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} {5FD0133B-69E5-4474-9B67-9FD1D0150C70} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} {39F49484-872A-489D-8E6B-3BC532DD571D} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} + {E8831F32-11D7-D42C-E43C-711998BC357A} = {04E3E11E-B47D-4599-8AFC-50515A95E715} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6} diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets index 149c3ae323b..57830d3638c 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets @@ -26,7 +26,8 @@ + Condition="Exists('$(MSBuildThisFileDirectory)..\tools\Xamarin.Android.Common.Debugging.props') And '$(DesignTimeBuild)' != 'true' "/> + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json b/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json index a61053ed7d1..50fc5a22030 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.NET.Sdk.Android/WorkloadManifest.in.json @@ -15,8 +15,8 @@ ], "platforms": [ "win-x64", "win-arm64", "linux-x64", "linux-arm64", "osx-x64", "osx-arm64" ], "extends" : [ - "microsoft-net-runtime-android-net8", - "microsoft-net-runtime-android-aot-net8", + "microsoft-net-runtime-android-net9", + "microsoft-net-runtime-android-aot-net9", "microsoft-net-runtime-android", "microsoft-net-runtime-android-aot" ] diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs index 9de0d72827b..a9b50ac09ce 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectAssemblyFilesForArchive.cs @@ -22,14 +22,7 @@ public class CollectAssemblyFilesToCompress : AndroidTask [Required] public string AssemblyCompressionDirectory { get; set; } = ""; - [Required] - public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); - - [Required] - public string ApkOutputPath { get; set; } = ""; - - [Required] - public string AppSharedLibrariesDir { get; set; } = ""; + public bool EmbedAssemblies { get; set; } [Required] public bool EnableCompression { get; set; } @@ -62,9 +55,9 @@ public override bool RunTask () ResolvedFrameworkAssembliesOutput = ResolvedFrameworkAssemblies; ResolvedUserAssembliesOutput = ResolvedUserAssemblies; - DSOWrapperGenerator.Config dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); - bool compress = !IncludeDebugSymbols && EnableCompression; - IDictionary>? compressedAssembliesInfo = null; + // We aren't going to compress any assemblies + if (IncludeDebugSymbols || !EnableCompression || !EmbedAssemblies) + return true; var assemblies_to_compress = new List (); var compressed_assemblies_info = GetCompressedAssemblyInfo (); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index f61816ce6f8..71d40e8ec4e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -72,6 +72,14 @@ public class GenerateJavaStubs : AndroidTask [Required] public string AndroidRuntime { get; set; } = ""; + public string CodeGenerationTarget { get; set; } = ""; + + [Required] + public string TargetName { get; set; } = ""; + + AndroidRuntime androidRuntime; + JavaPeerStyle codeGenerationTarget; + internal const string AndroidSkipJavaStubGeneration = "AndroidSkipJavaStubGeneration"; public override bool RunTask () @@ -243,10 +251,23 @@ void Run (bool useMarshalMethods) internal static Dictionary MaybeGetArchAssemblies (Dictionary> dict, AndroidTargetArch arch) { - if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.MonoVM && - androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { - Log.LogDebugMessage ($"Skipping MonoRuntimeProvider generation for: {androidRuntime}"); - return; + if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { + // Create additional runtime provider java sources. + bool isMonoVM = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM; + string providerTemplateFile = isMonoVM ? + "MonoRuntimeProvider.Bundled.java" : + "NativeAotRuntimeProvider.java"; + string providerTemplate = GetResource (providerTemplateFile); + + foreach (var provider in additionalProviders) { + var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); + var real_provider = isMonoVM ? + Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : + Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); + Files.CopyIfStringChanged (contents, real_provider); + } + } else { + Log.LogDebugMessage ($"Skipping android.content.ContentProvider generation for: {androidRuntime}"); } // For NativeAOT, generate JavaInteropRuntime.java @@ -304,7 +325,7 @@ IList MergeManifest (NativeCodeGenState codeGenState, Dictionary MergeManifest (NativeCodeGenState codeGenState, Dictionary allJavaTypes, List javaTypesForJCW) = ScanForJavaTypes (resolver, tdCache, assemblies, userAssemblies, useMarshalMethods); var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache, useMarshalMethods); var jcwGenerator = new JCWGenerator (Log, jcwContext) { - CodeGenerationTarget = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM ? JavaPeerStyle.XAJavaInterop1 : JavaPeerStyle.JavaInterop1 + CodeGenerationTarget = codeGenerationTarget, }; bool success; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs index ab297dd6d29..ba6414bc93e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs @@ -24,6 +24,9 @@ public class WrapAssembliesAsSharedLibraries : AndroidTask [Required] public string AndroidBinUtilsDirectory { get; set; } = ""; + [Required] + public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + public bool IncludeDebugSymbols { get; set; } [Required] @@ -42,7 +45,7 @@ public class WrapAssembliesAsSharedLibraries : AndroidTask public override bool RunTask () { - var wrapper_config = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, IntermediateOutputPath); + var wrapper_config = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); var files = new PackageFileListBuilder (); if (UseAssemblyStore) 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 be94e0bcbf7..0d09c5250f4 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 @@ -5,34 +5,34 @@ "Size": 3036 }, "classes.dex": { - "Size": 22444 + "Size": 22484 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 18296 + "Size": 18288 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 86352 + "Size": 86688 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 116920 + "Size": 117712 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22408 + "Size": 22384 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24376 + "Size": 24392 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { "Size": 25336 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 634384 + "Size": 628216 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20040 + "Size": 20056 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21584 + "Size": 21480 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 20024 @@ -44,10 +44,10 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1501240 + "Size": 1524752 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3196512 + "Size": 3101112 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71976 @@ -62,7 +62,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 18264 + "Size": 19536 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 3111445 + "PackageSize": 3078677 } \ 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 b3173a6f72f..ab4f60772ce 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 @@ -5,7 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9172764 + "Size": 9172540 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -35,22 +35,22 @@ "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 94736 + "Size": 94792 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 524256 + "Size": 535520 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22408 + "Size": 22432 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21448 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23072 + "Size": 23096 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 29792 + "Size": 29896 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { "Size": 36304 @@ -59,7 +59,7 @@ "Size": 25776 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23840 + "Size": 23856 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { "Size": 19608 @@ -71,31 +71,31 @@ "Size": 42480 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24416 + "Size": 24440 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19448 + "Size": 19464 }, "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { "Size": 28456 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 24688 + "Size": 24704 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19848 + "Size": 19864 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19424 + "Size": 19448 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30040 + "Size": 30056 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 49928 + "Size": 50312 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29472 + "Size": 29496 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { "Size": 33808 @@ -107,7 +107,7 @@ "Size": 38784 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 185800 + "Size": 185880 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { "Size": 90320 @@ -116,55 +116,55 @@ "Size": 41152 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21544 + "Size": 21568 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27064 + "Size": 27096 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 956552 + "Size": 958672 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 216720 + "Size": 216680 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { "Size": 62784 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 237120 + "Size": 236920 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 35584 + "Size": 35600 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { "Size": 20216 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21584 + "Size": 21480 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { - "Size": 54408 + "Size": 54168 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 19352 + "Size": 19368 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 20328 + "Size": 20344 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 21448 + "Size": 21472 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { "Size": 81248 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 183584 + "Size": 186352 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19248 + "Size": 19272 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19264 + "Size": 19280 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 22096 @@ -245,10 +245,10 @@ "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1501240 + "Size": 1524624 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3196512 + "Size": 3101160 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71976 @@ -263,7 +263,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 349440 + "Size": 349384 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -416,7 +416,7 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { "Size": 98577 @@ -2486,5 +2486,5 @@ "Size": 812848 } }, - "PackageSize": 10947851 + "PackageSize": 10923275 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index f24db218d69..cb42ffafaac 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -94,7 +94,7 @@ internal class ManifestDocument public bool ForceDebuggable { get; set; } public string VersionName { get; set; } public IVersionResolver VersionResolver { get; set; } = new MonoAndroidHelperVersionResolver (); - public string AndroidRuntime { get; set; } = "MonoVM"; + public AndroidRuntime AndroidRuntime { get; set; } string versionCode; diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 2ae443e5d40..997dc3bde35 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1527,6 +1527,7 @@ because xbuild doesn't support framework reference assemblies. - + + UseAssemblyStore="$(AndroidUseAssemblyStore)" + ResolvedRuntimePacks="@(ResolvedRuntimePack)"> diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index b94ad11879f..a1cee1367a6 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -586,11 +586,11 @@ else() add_subdirectory(mono/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 - ) + 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 + ) endif() if (IS_CLR_RUNTIME) diff --git a/src/native/common/include/shared/log_level.hh b/src/native/common/include/shared/log_level.hh index 66b1cae5097..fc7a7566910 100644 --- a/src/native/common/include/shared/log_level.hh +++ b/src/native/common/include/shared/log_level.hh @@ -1,112 +1,26 @@ #pragma once #include -#include -#include -#include - -#include "java-interop-logger.h" -#include "log_level.hh" - -// We redeclare macros here -#if defined(log_debug) -#undef log_debug -#endif - -#if defined(log_info) -#undef log_info -#endif - -#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ - do { \ - if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ - } \ - } while (0) - -// -// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec -// - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) namespace xamarin::android { - // 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; -} - -template [[gnu::always_inline]] -static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Debug, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); + 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 + }; } - -[[gnu::always_inline]] -static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Info, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); -} - -extern unsigned int log_categories; diff --git a/src/native/mono/monodroid/internal-pinvokes.cc b/src/native/mono/monodroid/internal-pinvokes.cc index 7c3dbab4933..41a98f6243d 100644 --- a/src/native/mono/monodroid/internal-pinvokes.cc +++ b/src/native/mono/monodroid/internal-pinvokes.cc @@ -134,13 +134,6 @@ monodroid_clear_gdb_wait () MonodroidRuntime::set_monodroid_gdb_wait (false); } -void* -_monodroid_get_identity_hash_code (JNIEnv *env, void *v) -{ - intptr_t rv = env->CallStaticIntMethod (MonodroidRuntime::get_java_class_System (), MonodroidRuntime::get_java_class_method_System_identityHashCode (), v); - return (void*) rv; -} - void* _monodroid_timezone_get_default_id () { diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index abbaa95bb79..aa5df834a37 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -129,7 +129,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l arg > 0, [&arg_name, &sloc] { return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a valid pointer", + "%s: parameter '%s' must be a positive integer", xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), arg_name ); From 6b8726845349663f1803dd4220698dc338da3c8b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 21 Feb 2025 13:15:32 +0100 Subject: [PATCH 117/143] Typemaps use type token ids again --- .../Android.Runtime/RuntimeNativeMethods.cs | 2 +- src/Mono.Android/Java.Interop/TypeManager.cs | 19 ++++-- ...appingReleaseNativeAssemblyGeneratorCLR.cs | 7 +- src/native/clr/host/internal-pinvokes.cc | 4 +- src/native/clr/host/typemap.cc | 64 ++++++++++++++----- src/native/clr/include/host/typemap.hh | 2 +- .../include/runtime-base/internal-pinvokes.hh | 2 +- src/native/clr/include/runtime-base/util.hh | 13 ++++ src/native/clr/include/xamarin-app.hh | 1 + 9 files changed, 84 insertions(+), 30 deletions(-) diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index 8965d50b114..0c0963c84f7 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -93,7 +93,7 @@ internal static class RuntimeNativeMethods internal static extern IntPtr clr_typemap_managed_to_java (string fullName, IntPtr mvid); [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr clr_typemap_java_to_managed (string fullName); + internal static extern bool clr_typemap_java_to_managed (string java_type_name, out IntPtr managed_assembly_name, out uint managed_type_token_id); [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index a8744e5f0f1..81ee5d6da47 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -229,17 +229,24 @@ static Type monovm_typemap_java_to_managed (string java_type_name) return monodroid_typemap_java_to_managed (java_type_name); } - [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Value of java_type_name isn't statically known.")] + [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Value of java_type_name isn't statically known.")] static Type? clr_typemap_java_to_managed (string java_type_name) { - IntPtr managedTypeNamePointer = RuntimeNativeMethods.clr_typemap_java_to_managed (java_type_name); - if (managedTypeNamePointer == IntPtr.Zero) { + bool result = RuntimeNativeMethods.clr_typemap_java_to_managed (java_type_name, out IntPtr managedAssemblyNamePointer, out uint managedTypeTokenId); + if (!result || managedAssemblyNamePointer == IntPtr.Zero) { return null; } - string managedTypeName = Marshal.PtrToStringAnsi (managedTypeNamePointer); - Logger.Log (LogLevel.Info, "monodroid", $"clr_typemap_java_to_managed ('{java_type_name}') returned '{managedTypeName}'"); - Type ret = Type.GetType (managedTypeName); + string managedAssemblyName = Marshal.PtrToStringAnsi (managedAssemblyNamePointer); + Assembly assembly = Assembly.Load (managedAssemblyName); + Type? ret = null; + foreach (Module module in assembly.Modules) { + ret = module.ResolveType ((int)managedTypeTokenId); + if (ret != null) { + break; + } + } + Logger.Log (LogLevel.Info, "monodroid", $"Loaded type: {ret}"); return ret; } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs index d2871c1e245..5c62f0df88f 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs @@ -173,6 +173,9 @@ sealed class TypeMapJava [NativeAssembler (UsesDataProvider = true)] public uint managed_type_name_index; + [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public uint managed_type_token_id; + [NativeAssembler (UsesDataProvider = true)] public uint java_name_index; } @@ -398,8 +401,7 @@ void InitJavaMap (ConstructionState cs) TypeMapJava map_entry; foreach (TypeMapGenerator.TypeMapReleaseEntry entry in mappingData.JavaTypes) { string assemblyName = mappingData.Modules[entry.ModuleIndex].AssemblyName; - string fullManagedTypeName = $"{entry.ManagedTypeName}, {assemblyName}"; - uint managedTypeNameIndex = GetEntryIndex (fullManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); + uint managedTypeNameIndex = GetEntryIndex (entry.ManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); cs.JavaNames.Add (entry.JavaName); map_entry = new TypeMapJava { @@ -407,6 +409,7 @@ void InitJavaMap (ConstructionState cs) module_index = (uint)entry.ModuleIndex, // UInt32.MaxValue, managed_type_name_index = managedTypeNameIndex, + managed_type_token_id = entry.Token, java_name_index = (uint)(cs.JavaNames.Count - 1), JavaName = entry.JavaName, }; diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 4f34ebd2d98..afa27f9706c 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -28,9 +28,9 @@ const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mv return TypeMapper::typemap_managed_to_java (typeName, mvid); } -const char* clr_typemap_java_to_managed (const char *typeName) noexcept +bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept { - return TypeMapper::typemap_java_to_managed (typeName); + return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 7b7fa77e2ef..8f1df3cce0f 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -14,10 +15,6 @@ namespace { static inline constexpr size_t MVID_SIZE = 16; static inline constexpr size_t NUM_HYPHENS = 4; static inline constexpr size_t BUF_SIZE = (MVID_SIZE * 2) + NUM_HYPHENS + 1; - static inline std::array hex_map { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', - }; public: explicit MonoGuidString (const uint8_t *mvid) noexcept @@ -29,8 +26,8 @@ namespace { // In the caller we trust, we have no way to validate the size here auto to_hex = [this, &mvid] (size_t &dest_idx, size_t src_idx) { - _ascii_form[dest_idx++] = hex_map[(mvid[src_idx] & 0xf0) >> 4]; - _ascii_form[dest_idx++] = hex_map[mvid[src_idx] & 0x0f]; + Util::to_hex (mvid[src_idx], _ascii_form[dest_idx], _ascii_form[dest_idx + 1]); + dest_idx += 2; }; auto hyphen = [this] (size_t &dest_idx) { @@ -240,7 +237,7 @@ auto TypeMapper::typemap_managed_to_java (const char *typeName, const uint8_t *m #if defined(DEBUG) [[gnu::flatten]] -auto TypeMapper::typemap_java_to_managed (const char *typeName) noexcept -> const char* +auto TypeMapper::typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { Helpers::abort_application ("typemap_java_to_managed not implemented for debug builds yet"); } @@ -258,32 +255,65 @@ auto TypeMapper::find_java_to_managed_entry (hash_t name_hash) noexcept -> const } [[gnu::flatten]] -auto TypeMapper::typemap_java_to_managed (const char *typeName) noexcept -> const char* +auto TypeMapper::typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { - if (typeName == nullptr) [[unlikely]] { - return nullptr; + if (java_type_name == nullptr || assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { + if (java_type_name == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}", + "java_type_name"sv, + __PRETTY_FUNCTION__ + ); + } + + if (assembly_name == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}", + "assembly_name"sv, + __PRETTY_FUNCTION__ + ); + } + + if (managed_type_token_id == nullptr) { + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}", + "managed_type_token_id"sv, + __PRETTY_FUNCTION__ + ); + } + + return false; } - hash_t name_hash = xxhash::hash (typeName, strlen (typeName)); + hash_t name_hash = xxhash::hash (java_type_name, strlen (java_type_name)); TypeMapJava const* java_entry = find_java_to_managed_entry (name_hash); if (java_entry == nullptr) { log_info ( LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", - optional_string (typeName), + optional_string (java_type_name), name_hash ); - return nullptr; + return false; } + TypeMapModule const &module = managed_to_java_map[java_entry->module_index]; + *assembly_name = managed_assembly_names[module.assembly_name_index]; + *managed_type_token_id = java_entry->managed_type_token_id; + log_debug ( LOG_ASSEMBLY, - "Java type '{}' corresponds to managed type '{}' ({:p}", - optional_string (typeName), + "Java type '{}' corresponds to managed type '{}' (token 0x{:x} in assembly '{}')", + optional_string (java_type_name), optional_string (managed_type_names[java_entry->managed_type_name_index]), - reinterpret_cast(managed_type_names[java_entry->managed_type_name_index]) + *managed_type_token_id, + optional_string (*assembly_name) ); - return managed_type_names[java_entry->managed_type_name_index]; + + return true; } #endif // ndef DEBUG diff --git a/src/native/clr/include/host/typemap.hh b/src/native/clr/include/host/typemap.hh index 5e535bde732..f695f0ce5d4 100644 --- a/src/native/clr/include/host/typemap.hh +++ b/src/native/clr/include/host/typemap.hh @@ -11,7 +11,7 @@ namespace xamarin::android { { public: static auto typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char*; - static auto typemap_java_to_managed (const char *typeName) noexcept -> const char*; + static auto typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_doken_id) noexcept -> bool; private: #if defined(RELEASE) diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index b2c162ecd85..44ba6fb99cb 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -9,7 +9,7 @@ void _monodroid_gref_log (const char *message) noexcept; int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept; void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept; -const char* clr_typemap_java_to_managed (const char *typeName) noexcept; +bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept; void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; void monodroid_free (void *ptr) noexcept; diff --git a/src/native/clr/include/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 78100e05a71..efa658fa782 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -41,12 +41,25 @@ namespace xamarin::android { class Util { + static constexpr inline std::array hex_map { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + }; + public: static int create_directory (const char *pathname, mode_t mode); static void create_public_directory (std::string_view const& dir); static auto monodroid_fopen (std::string_view const& filename, std::string_view const& mode) noexcept -> FILE*; static void set_world_accessable (std::string_view const& path); + // Puts higher half of the `value` byte as a hexadecimal character in `high_half` and + // the lower half in `low_half` + static void to_hex (uint8_t value, char &high_half, char &low_half) noexcept + { + high_half = hex_map[(value & 0xf0) >> 4]; + low_half = hex_map[value & 0x0f]; + } + static auto should_log (LogCategories category) noexcept -> bool { return (log_categories & category) != 0; diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index f0004675f75..41b82d3ff2d 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -93,6 +93,7 @@ struct TypeMapJava { uint32_t module_index; uint32_t managed_type_name_index; + uint32_t managed_type_token_id; uint32_t java_name_index; }; #endif From 9f5d9117612e1fe418a590b931158983fc2c0782 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 21 Feb 2025 17:37:08 +0100 Subject: [PATCH 118/143] Fix after rebase From dece52f6c03f7c4541ae6db64e09a0384d43cb1a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 21 Feb 2025 20:23:04 +0100 Subject: [PATCH 119/143] [WIP] Broken, tbc on Monday --- .../targets/Microsoft.Android.Sdk.Aot.targets | 2 +- ...oft.Android.Sdk.AssemblyResolution.targets | 27 --- .../Tasks/CollectNativeFilesForArchive.cs | 4 +- .../CollectRuntimeConfigFilesForArchive.cs | 4 +- .../Tasks/GetAotArguments.cs | 4 +- .../Tasks/LinkApplicationSharedLibraries.cs | 6 +- .../Tasks/RecreateResolvedRuntimePacks.cs | 167 ------------------ .../Tasks/WrapAssembliesAsSharedLibraries.cs | 4 +- .../Xamarin.Android.Common.targets | 8 +- 9 files changed, 16 insertions(+), 210 deletions(-) delete mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 5f5c148acb7..6b4b39eee7d 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -92,7 +92,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). Profiles="@(AndroidAotProfile)" StripLibraries="$(_AndroidAotStripLibraries)" ZipAlignmentPages="$(AndroidZipAlignment)" - ResolvedRuntimePacks="@(ResolvedRuntimePack)"> + RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index dfd733b4fb5..9a8f99dc8fa 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 @@ -13,9 +13,6 @@ _ResolveAssemblies MSBuild target. - - - - - - - - - - - - - <_InnerIntermediateOutputPath Condition=" '$(RuntimeIdentifier)' == '' ">$(IntermediateOutputPath)%(_RIDs.Identity)\ @@ -263,17 +247,6 @@ _ResolveAssemblies MSBuild target. <_ExcludedNativeLibraries Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " Include="libmono-android.release" /> - - - - - - - <_ResolvedNativeLibraries Remove="@(_IgnoreSharedLibraries)" /> - - (); + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); [Required] public string IntermediateOutputPath { get; set; } = ""; @@ -71,7 +71,7 @@ public class CollectNativeFilesForArchive : AndroidTask public override bool RunTask () { var apk = new PackageFileListBuilder (); - var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); + var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, RuntimePackLibraryDirectories, IntermediateOutputPath); var outputFiles = new List { ApkOutputPath diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs index 14a8c3a0946..2be75d0bb99 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs @@ -20,7 +20,7 @@ public class CollectRuntimeConfigFilesForArchive : AndroidTask public string AndroidBinUtilsDirectory { get; set; } = ""; [Required] - public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); [Required] public string IntermediateOutputPath { get; set; } = ""; @@ -36,7 +36,7 @@ public class CollectRuntimeConfigFilesForArchive : AndroidTask public override bool RunTask () { var files = new PackageFileListBuilder (); - var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); + var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, RuntimePackLibraryDirectories, IntermediateOutputPath); // We will place rc.bin in the `lib` directory next to the blob, to make startup slightly faster, as we will find the config file right after we encounter // our assembly store. Not only that, but also we'll be able to skip scanning the `base.apk` archive when split configs are enabled (which they are in 99% diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs index 2870939144a..890be9462ee 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs @@ -33,7 +33,7 @@ public abstract class GetAotArguments : AsyncTask public string TargetName { get; set; } = ""; [Required] - public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); /// /// Will be blank in .NET 6+ @@ -298,7 +298,7 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP libs.Add (Path.Combine (androidLibPath, "libc.so")); libs.Add (Path.Combine (androidLibPath, "libm.so")); } else if (!UseAndroidNdk && EnableLLVM) { - string libstubsPath = MonoAndroidHelper.GetLibstubsArchDirectoryPath (ResolvedRuntimePacks, arch); + string libstubsPath = MonoAndroidHelper.GetLibstubsArchDirectoryPath (RuntimePackLibraryDirectories, arch); libs.Add (Path.Combine (libstubsPath, "libc.so")); libs.Add (Path.Combine (libstubsPath, "libm.so")); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 3318f983a59..37dba66bfaa 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -44,7 +44,7 @@ sealed class InputFiles public string AndroidBinUtilsDirectory { get; set; } [Required] - public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); [Required] public bool TargetsCLR { get; set; } @@ -212,8 +212,8 @@ InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem { AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi); var libDirs = new HashSet (StringComparer.OrdinalIgnoreCase) { - MonoAndroidHelper.GetNativeLibsRootDirectoryPath (Log, ResolvedRuntimePacks, arch), - MonoAndroidHelper.GetLibstubsArchDirectoryPath (ResolvedRuntimePacks, arch), + MonoAndroidHelper.GetNativeLibsRootDirectoryPath (Log, RuntimePackLibraryDirectories, arch), + MonoAndroidHelper.GetLibstubsArchDirectoryPath (RuntimePackLibraryDirectories, arch), }; string RID = MonoAndroidHelper.AbiToRid (abi); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs b/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs deleted file mode 100644 index 3c660535005..00000000000 --- a/src/Xamarin.Android.Build.Tasks/Tasks/RecreateResolvedRuntimePacks.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using Microsoft.Android.Build.Tasks; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -namespace Xamarin.Android.Tasks; - -public class RecreateResolvedRuntimePacks : AndroidTask -{ - public override string TaskPrefix => "RRRP"; - - static readonly string[] RuntimeLibrariesMonoVM = [ - "libmono-android.debug.so", - "libmono-android.release.so", - ]; - - static readonly string[] RuntimeLibrariesCoreCLR = [ - "libnet-android.debug.so", - "libnet-android.release.so", - ]; - - static readonly string[] LibraryNamesToIgnore = [ - "libarchive-dso-stub.so", - "libc.so", - "libdl.so", - "liblog.so", - "libm.so", - "libz.so", - ]; - - [Required] - public ITaskItem[] ResolvedNativeLibraries { get; set; } - - [Required] - public string AndroidRuntime { get; set; } - - [Output] - public ITaskItem[] ResolvedRuntimePacks { get; set; } - - // Contains items for libraries which are to be removed from @(_ResolvedNativeLibraries), so that - // they aren't copied to the AAB/APK. There's a number of such libraries in our runtime packs, they - // are used only at build time and mustn't be included in the application archives. - [Output] - public ITaskItem[] SharedLibrariesToIgnore { get; set; } - - public override bool RunTask () - { - var ignoreLibNames = new List (); - foreach (string libName in LibraryNamesToIgnore) { - ignoreLibNames.Add (String.Format ("{0}native{0}{1}", Path.DirectorySeparatorChar, libName)); - } - - string[] runtimeLibraries; - if (String.Compare ("MonoVM", AndroidRuntime, StringComparison.OrdinalIgnoreCase) == 0) { - runtimeLibraries = RuntimeLibrariesMonoVM; - } else if (String.Compare ("CoreCLR", AndroidRuntime, StringComparison.OrdinalIgnoreCase) == 0) { - runtimeLibraries = RuntimeLibrariesCoreCLR; - } else { - throw new NotSupportedException ($"Internal error: unsupported runtime flavor '{AndroidRuntime}'"); - } - - // We need to find `libc.so` that comes from one of our runtime packs - var libcPath = String.Format ("{0}native{0}libc.so", Path.DirectorySeparatorChar); - var runtimePacks = new Dictionary (StringComparer.OrdinalIgnoreCase); - var maybeIgnoreLibs = new List (); - var runtimePackPaths = new List (); - - foreach (ITaskItem library in ResolvedNativeLibraries) { - foreach (string libPathTail in ignoreLibNames) { - if (!library.ItemSpec.EndsWith (libPathTail, StringComparison.OrdinalIgnoreCase)) { - continue; - } - - maybeIgnoreLibs.Add (library); - break; - } - - if (!library.ItemSpec.EndsWith (libcPath, StringComparison.OrdinalIgnoreCase)) { - continue; - } - - if (!GetMetadata (library, "RuntimeIdentifier", out string? rid) || runtimePacks.ContainsKey (rid)) { - continue; - } - - if (!GetMetadata (library, "NuGetPackageId", out string? nugetPackageId)) { - continue; - } - - if (!GetMetadata (library, "NuGetPackageVersion", out string? nugetPackageVersion)) { - continue; - } - - string tail = String.Format ("{0}runtimes{0}{1}{2}", Path.DirectorySeparatorChar, rid, libcPath); - int tailIndex = library.ItemSpec.IndexOf (tail); - if (tailIndex < 0) { - continue; - } - string packageDir = library.ItemSpec.Substring (0, tailIndex); - - // Archive DSO stub must always exist - if (!PackNativeFileExists (packageDir, rid, DSOWrapperGenerator.StubFileName)) { - Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain '{DSOWrapperGenerator.StubFileName}'. Pack ignored."); - continue; - } - - // Either one of the runtime libraries must exist - bool runtimeLibraryFound = false; - foreach (string runtimeLibrary in runtimeLibraries) { - if (PackNativeFileExists (packageDir, rid, runtimeLibrary)) { - runtimeLibraryFound = true; - continue; - } - Log.LogDebugMessage ($"Runtime library '{runtimeLibrary}' not found in pack '{packageDir}'"); - } - if (!runtimeLibraryFound) { - Log.LogDebugMessage ($"Runtime pack '{packageDir}' doesn't contain any {AndroidRuntime} runtime shared libraries. Pack ignored."); - continue; - } - - var pack = new TaskItem (nugetPackageId); - pack.SetMetadata ("FrameworkName", "Microsoft.Android"); - pack.SetMetadata ("NuGetPackageId", nugetPackageId); - pack.SetMetadata ("NuGetPackageVersion", nugetPackageVersion); - pack.SetMetadata ("RuntimeIdentifier", rid); - pack.SetMetadata ("PackageDirectory", packageDir); - - runtimePackPaths.Add (packageDir); - runtimePacks.Add (rid, pack); - } - - ResolvedRuntimePacks = runtimePacks.Values.ToArray (); - - var librariesToIgnore = new List (); - foreach (string path in runtimePackPaths) { - string runtimePackPath = path; - if (path[path.Length - 1] != Path.DirectorySeparatorChar) { - runtimePackPath = $"{path}{Path.DirectorySeparatorChar}"; - } - - foreach (ITaskItem library in maybeIgnoreLibs) { - if (library.ItemSpec.StartsWith (runtimePackPath)) { - librariesToIgnore.Add (library); - } - } - }; - SharedLibrariesToIgnore = librariesToIgnore.ToArray (); - - return !Log.HasLoggedErrors; - - bool GetMetadata (ITaskItem item, string metadataName, out string? metadataValue) - { - metadataValue = item.GetMetadata (metadataName); - return !String.IsNullOrEmpty (metadataValue); - } - - bool PackNativeFileExists (string packageDir, string rid, string fileName) - { - string packFilePath = Path.Combine (packageDir, "runtimes", rid, "native", fileName); - return File.Exists (packFilePath); - } - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs index ba6414bc93e..4a83aa4266e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/WrapAssembliesAsSharedLibraries.cs @@ -25,7 +25,7 @@ public class WrapAssembliesAsSharedLibraries : AndroidTask public string AndroidBinUtilsDirectory { get; set; } = ""; [Required] - public ITaskItem[] ResolvedRuntimePacks { get; set; } = Array.Empty (); + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); public bool IncludeDebugSymbols { get; set; } @@ -45,7 +45,7 @@ public class WrapAssembliesAsSharedLibraries : AndroidTask public override bool RunTask () { - var wrapper_config = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, ResolvedRuntimePacks, IntermediateOutputPath); + var wrapper_config = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, RuntimePackLibraryDirectories, IntermediateOutputPath); var files = new PackageFileListBuilder (); if (UseAssemblyStore) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 997dc3bde35..dca60b64eef 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2093,7 +2093,7 @@ because xbuild doesn't support framework reference assemblies. AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" ZipAlignmentPages="$(AndroidZipAlignment)" TargetsCLR="$(_AndroidUseCLR)" - ResolvedRuntimePacks="@(ResolvedRuntimePack)" + RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)" /> @@ -2220,7 +2220,7 @@ because xbuild doesn't support framework reference assemblies. ResolvedAssemblies="@(_BuildApkAssembliesToAddToArchive)" SupportedAbis="@(_BuildTargetAbis)" UseAssemblyStore="$(AndroidUseAssemblyStore)" - ResolvedRuntimePacks="@(ResolvedRuntimePack)"> + RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> @@ -2247,7 +2247,7 @@ because xbuild doesn't support framework reference assemblies. IntermediateOutputPath="$(IntermediateOutputPath)" RuntimeConfigBinFilePath="$(_BinaryRuntimeConfigPath)" SupportedAbis="@(_BuildTargetAbis)" - ResolvedRuntimePacks="@(ResolvedRuntimePack)"> + RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> @@ -2265,7 +2265,7 @@ because xbuild doesn't support framework reference assemblies. ZipAlignmentPages="$(AndroidZipAlignment)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" IntermediateOutputPath="$(IntermediateOutputPath)" - ResolvedRuntimePacks="@(ResolvedRuntimePack)"> + RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> From 69a6713cbd56f7cbee1c5f1252ee8a430074ce9c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 24 Feb 2025 11:10:17 +0100 Subject: [PATCH 120/143] Use a local CoreCLR runtime build, if requested and present --- .../targets/Microsoft.Android.Sdk.CoreCLR.targets | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets index 82970b039f9..bef2c60a58f 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets @@ -12,4 +12,17 @@ This file contains the CoreCLR-specific MSBuild logic for .NET for Android. <_AndroidRuntimePackRuntime>CoreCLR + + + <_DotNetRuntimeRepo>$(_CLRLocalRuntimePath) + <_DotNetRuntimeConfiguration Condition=" '$(_DotNetRuntimeConfiguration)' == '' ">Release + + + + + + From cea74326aaff3328d4f0855fa6d970c1f889b40b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 24 Feb 2025 11:15:38 +0100 Subject: [PATCH 121/143] Forget me not --- src/native/clr/host/host.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 0c84fe8637e..e68a4d3ec11 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -30,6 +30,7 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size bool Host::clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept { + // TODO: `path` might be a full path, make sure it isn't log_debug (LOG_DEFAULT, "clr_bundle_probe (\"{}\"...)", path); if (data_start == nullptr || size == nullptr) { return false; // TODO: abort instead? From 5f6619906aaf2f50158ac18e4ea874e09d112a78 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 24 Feb 2025 12:23:16 +0100 Subject: [PATCH 122/143] [WIP] runtime pack library dirs discovery --- ...oft.Android.Sdk.AssemblyResolution.targets | 18 +++- .../ProcessRuntimePackLibraryDirectories.cs | 101 ++++++++++++++++++ 2 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/ProcessRuntimePackLibraryDirectories.cs 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 9a8f99dc8fa..54da968c370 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets @@ -12,6 +12,7 @@ _ResolveAssemblies MSBuild target. + @@ -114,8 +115,19 @@ _ResolveAssemblies MSBuild target. + + + + + + - + @@ -131,10 +143,6 @@ _ResolveAssemblies MSBuild target. <_ResolvedJavaLibraries Include="@(ResolvedFileToPublish)" Condition=" '%(ResolvedFileToPublish.Extension)' == '.jar' " /> - - - - "FRPLD"; + + static readonly HashSet NativeLibraryNames = new (StringComparer.OrdinalIgnoreCase) { + "libarchive-dso-stub.so", + "libc.so", + "libdl.so", + "liblog.so", + "libm.so", + "libz.so", + }; + + [Required] + public ITaskItem[] ResolvedFilesToPublish { get; set; } = Array.Empty (); + + [Output] + public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); + + [Output] + public ITaskItem[] NativeLibrariesToRemove { get; set; } = Array.Empty (); + + public override bool RunTask () + { + var libDirs = new List (); + var librariesToRemove = new List (); + var seenRIDs = new HashSet (StringComparer.OrdinalIgnoreCase); + + foreach (ITaskItem item in ResolvedFilesToPublish) { + if (!IsInSupportedRuntimePack (item)) { + continue; + } + + string? fileName = Path.GetFileName (item.ItemSpec); + if (String.IsNullOrEmpty (fileName) || !NativeLibraryNames.Contains (fileName)) { + continue; + } + + string? rid = item.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (rid)) { + Log.LogDebugMessage ($"Ignoring item '{item}' because it contains no runtime identifier metadata"); + continue; + } + + if (!seenRIDs.Contains (rid)) { + string? dirName = Path.GetDirectoryName (item.ItemSpec); + if (String.IsNullOrEmpty (dirName)) { + Log.LogDebugMessage ($"Item '{item}' path doesn't contain full file path"); + } else { + libDirs.Add (MakeLibDirItem (item, dirName)); + } + seenRIDs.Add (rid); + Log.LogDebugMessage ($"Discovered runtime pack library directory for '{rid}': {dirName}"); + } + + librariesToRemove.Add (item); + Log.LogDebugMessage ($"Item '{item}' will be removed from the set of native libraries to publish"); + } + + RuntimePackLibraryDirectories = libDirs.ToArray (); + NativeLibrariesToRemove = librariesToRemove.ToArray (); + + return !Log.HasLoggedErrors; + } + + ITaskItem MakeLibDirItem (ITaskItem sourceItem, string dir) + { + var ret = new TaskItem (dir); + sourceItem.CopyMetadataTo (ret); + + // These make no sense for directories, remove just to be safe + ret.RemoveMetadata ("CopyLocal"); + ret.RemoveMetadata ("CopyToPublishDirectory"); + ret.RemoveMetadata ("DestinationSubPath"); + ret.RemoveMetadata ("RelativePath"); + return ret; + } + + bool IsInSupportedRuntimePack (ITaskItem item) + { + string? NuGetPackageId = item.GetMetadata ("NuGetPackageId"); + if (String.IsNullOrEmpty (NuGetPackageId)) { + return false; + } + + return NuGetPackageId.StartsWith ("Microsoft.Android.Runtime.CoreCLR.", StringComparison.OrdinalIgnoreCase) || + NuGetPackageId.StartsWith ("Microsoft.Android.Runtime.Mono.", StringComparison.OrdinalIgnoreCase); + } +} From a61d1eaee6577fb4db88b5e3912f401152d89a04 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 24 Feb 2025 16:31:22 +0100 Subject: [PATCH 123/143] Use discovered runtime pack native lib dirs --- .../targets/Microsoft.Android.Sdk.Aot.targets | 2 +- .../Tasks/GetAotArguments.cs | 8 ++- .../Tasks/LinkApplicationSharedLibraries.cs | 3 +- .../Utilities/DSOWrapperGenerator.cs | 13 ++-- .../Utilities/MonoAndroidHelper.cs | 64 +++---------------- .../Xamarin.Android.Common.targets | 14 ++-- 6 files changed, 29 insertions(+), 75 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 6b4b39eee7d..3e24b0d8c08 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -92,7 +92,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). Profiles="@(AndroidAotProfile)" StripLibraries="$(_AndroidAotStripLibraries)" ZipAlignmentPages="$(AndroidZipAlignment)" - RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs index 890be9462ee..fce21988f58 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs @@ -298,10 +298,12 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP libs.Add (Path.Combine (androidLibPath, "libc.so")); libs.Add (Path.Combine (androidLibPath, "libm.so")); } else if (!UseAndroidNdk && EnableLLVM) { - string libstubsPath = MonoAndroidHelper.GetLibstubsArchDirectoryPath (RuntimePackLibraryDirectories, arch); + string? libstubsPath = MonoAndroidHelper.GetRuntimePackNativeLibDir (arch, RuntimePackLibraryDirectories); - libs.Add (Path.Combine (libstubsPath, "libc.so")); - libs.Add (Path.Combine (libstubsPath, "libm.so")); + if (!String.IsNullOrEmpty (libstubsPath)) { + libs.Add (Path.Combine (libstubsPath, "libc.so")); + libs.Add (Path.Combine (libstubsPath, "libm.so")); + } } if (libs.Count > 0) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 37dba66bfaa..5ac7faebc82 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -212,8 +212,7 @@ InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem { AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi); var libDirs = new HashSet (StringComparer.OrdinalIgnoreCase) { - MonoAndroidHelper.GetNativeLibsRootDirectoryPath (Log, RuntimePackLibraryDirectories, arch), - MonoAndroidHelper.GetLibstubsArchDirectoryPath (RuntimePackLibraryDirectories, arch), + MonoAndroidHelper.GetRuntimePackNativeLibDir (arch, RuntimePackLibraryDirectories), }; string RID = MonoAndroidHelper.AbiToRid (abi); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs index 612c24b928a..3dd7b1863cb 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs @@ -55,20 +55,19 @@ public Config (Dictionary stubPaths, string androidBi // const ulong PayloadSectionAlignment = 0x4000; - public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDirectory, ITaskItem[] runtimePacks, string baseOutputDirectory) + public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDirectory, ITaskItem[] runtimePackLibraryDirs, string baseOutputDirectory) { var stubPaths = new Dictionary (); - foreach (ITaskItem maybePack in runtimePacks) { - if (!MonoAndroidHelper.IsAndroidRuntimePack (maybePack, out string? packRID) || String.IsNullOrEmpty (packRID)) { + foreach (ITaskItem packLibDir in runtimePackLibraryDirs) { + string ?packRID = packLibDir.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (packRID)) { continue; } - string packDir = MonoAndroidHelper.GetAndroidRuntimePackDir (maybePack); - string stubRelPath = Path.Combine ("runtimes", packRID, "native", StubFileName); - string stubPath = Path.Combine (packDir, stubRelPath); + string stubPath = Path.Combine (packLibDir.ItemSpec, StubFileName); if (!File.Exists (stubPath)) { - throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubRelPath}' does not exist in runtime pack at {packDir}"); + throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubPath}' does not exist in runtime pack at {packLibDir}"); } AndroidTargetArch arch = MonoAndroidHelper.RidToArch (packRID); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 02797f267fa..bd5f567cae6 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -570,67 +570,21 @@ static string GetToolsRootDirectoryRelativePath (string androidBinUtilsDirectory } #if MSBUILD - public static bool IsAndroidRuntimePack (ITaskItem maybePack, out string? packRID) + public static string? GetRuntimePackNativeLibDir (AndroidTargetArch arch, IEnumerable runtimePackLibDirs) { - string? framework = maybePack.GetMetadata ("FrameworkName"); - if (String.IsNullOrEmpty (framework) || String.Compare ("Microsoft.Android", framework, StringComparison.Ordinal) != 0) { - packRID = null; - return false; - } - - packRID = maybePack.GetMetadata ("RuntimeIdentifier"); - return !String.IsNullOrEmpty (packRID); - } - - public static string GetAndroidRuntimePackDir (ITaskItem pack) - { - return pack.GetMetadata ("PackageDirectory"); - } - - public static string GetAndroidRuntimePackNativeDir (ITaskItem[] runtimePacks, AndroidTargetArch arch) - { - string rid = ArchToRid (arch); - ITaskItem? androidRuntimePack = null; - - foreach (ITaskItem pack in runtimePacks) { - if (!IsAndroidRuntimePack (pack, out string? packRID) || String.Compare (rid, packRID, StringComparison.OrdinalIgnoreCase) != 0) { + foreach (ITaskItem item in runtimePackLibDirs) { + string? rid = item.GetMetadata ("RuntimeIdentifier"); + if (String.IsNullOrEmpty (rid)) { continue; } - androidRuntimePack = pack; - break; - } - - if (androidRuntimePack == null) { - throw new InvalidOperationException ($"Internal error: Android runtime pack for architecture {arch} not found"); - } - - string? packageDir = GetAndroidRuntimePackDir (androidRuntimePack); - if (String.IsNullOrEmpty (packageDir)) { - throw new InvalidOperationException ($"Internal error: Android runtime pack for architecture {arch} is missing package directory metadata"); - } - - return Path.Combine (packageDir, "runtimes", rid, "native"); - } - - public static string GetLibstubsArchDirectoryPath (ITaskItem[] runtimePacks, AndroidTargetArch arch) - { - return GetAndroidRuntimePackNativeDir (runtimePacks, arch); - } - - public static string GetDSOStubsRootDirectoryPath (ITaskItem[] runtimePacks, AndroidTargetArch arch) - { - return GetAndroidRuntimePackNativeDir (runtimePacks, arch); - } - - public static string GetNativeLibsRootDirectoryPath (TaskLoggingHelper log, ITaskItem[] runtimePacks, AndroidTargetArch arch) - { - log.LogWarning ("Potential runtime packs:"); - foreach (ITaskItem item in runtimePacks) { - log.LogWarning ($" {item}"); + AndroidTargetArch itemArch = RidToArch (rid); + if (itemArch == arch) { + return item.ItemSpec; + } } - return GetAndroidRuntimePackNativeDir (runtimePacks, arch); + return null; } #endif // MSBUILD diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index dca60b64eef..9d06b2fc896 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1474,7 +1474,7 @@ because xbuild doesn't support framework reference assemblies. - + @@ -1998,7 +1998,7 @@ because xbuild doesn't support framework reference assemblies. @@ -2093,7 +2093,7 @@ because xbuild doesn't support framework reference assemblies. AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" ZipAlignmentPages="$(AndroidZipAlignment)" TargetsCLR="$(_AndroidUseCLR)" - RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)" /> @@ -2220,7 +2220,7 @@ because xbuild doesn't support framework reference assemblies. ResolvedAssemblies="@(_BuildApkAssembliesToAddToArchive)" SupportedAbis="@(_BuildTargetAbis)" UseAssemblyStore="$(AndroidUseAssemblyStore)" - RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> @@ -2247,7 +2247,7 @@ because xbuild doesn't support framework reference assemblies. IntermediateOutputPath="$(IntermediateOutputPath)" RuntimeConfigBinFilePath="$(_BinaryRuntimeConfigPath)" SupportedAbis="@(_BuildTargetAbis)" - RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> @@ -2265,7 +2265,7 @@ because xbuild doesn't support framework reference assemblies. ZipAlignmentPages="$(AndroidZipAlignment)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" IntermediateOutputPath="$(IntermediateOutputPath)" - RuntimePackLibraryDirectories="@(RuntimePackLibraryDirectory)"> + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> From cc0be441aa34cfe790c7c3492cb6e28d017bd7e3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 24 Feb 2025 16:51:16 +0100 Subject: [PATCH 124/143] Fix build on CoreCLR after `main` rebase --- .../Tasks/GenerateJavaStubs.cs | 41 +++++++++---------- .../Xamarin.Android.Common.targets | 2 +- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 71d40e8ec4e..6209a8577b2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -251,25 +251,27 @@ void Run (bool useMarshalMethods) internal static Dictionary MaybeGetArchAssemblies (Dictionary> dict, AndroidTargetArch arch) { - if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { - // Create additional runtime provider java sources. - bool isMonoVM = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM; - string providerTemplateFile = isMonoVM ? - "MonoRuntimeProvider.Bundled.java" : - "NativeAotRuntimeProvider.java"; - string providerTemplate = GetResource (providerTemplateFile); - - foreach (var provider in additionalProviders) { - var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); - var real_provider = isMonoVM ? - Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : - Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); - Files.CopyIfStringChanged (contents, real_provider); - } - } else { - Log.LogDebugMessage ($"Skipping android.content.ContentProvider generation for: {androidRuntime}"); + // Create additional runtime provider java sources. + bool isMonoVM = androidRuntime switch { + Xamarin.Android.Tasks.AndroidRuntime.MonoVM => true, + Xamarin.Android.Tasks.AndroidRuntime.CoreCLR => true, + _ => false, + }; + + string providerTemplateFile = isMonoVM ? + "MonoRuntimeProvider.Bundled.java" : + "NativeAotRuntimeProvider.java"; + string providerTemplate = GetResource (providerTemplateFile); + + foreach (var provider in additionalProviders) { + var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); + var real_provider = isMonoVM ? + Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : + Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); + Files.CopyIfStringChanged (contents, real_provider); } + // For NativeAOT, generate JavaInteropRuntime.java if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) { const string fileName = "JavaInteropRuntime.java"; @@ -414,10 +416,7 @@ void WriteTypeMappings (NativeCodeGenState state) // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep` return; } - if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { - // TODO: CoreCLR typemaps will be emitted later - return; - } + Log.LogDebugMessage ($"Generating type maps for architecture '{state.TargetArch}'"); var tmg = new TypeMapGenerator (Log, state, androidRuntime); if (!tmg.Generate (Debug, SkipJniAddNativeMethodRegistrationAttributeScan, TypemapOutputDirectory, GenerateNativeAssembly)) { diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 9d06b2fc896..28a01bf23af 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1474,7 +1474,7 @@ because xbuild doesn't support framework reference assemblies. - + Date: Mon, 24 Feb 2025 18:57:32 +0100 Subject: [PATCH 125/143] Add some logs and update structure layout --- src/native/clr/host/assembly-store.cc | 2 ++ src/native/clr/host/host.cc | 2 +- src/native/clr/include/host/host.hh | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc index e5ee5edf897..661ad16ab4d 100644 --- a/src/native/clr/host/assembly-store.cc +++ b/src/native/clr/host/assembly-store.cc @@ -26,6 +26,7 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co uint32_t assembly_data_size = 0; #if defined (HAVE_LZ4) && defined (RELEASE) + log_debug (LOG_ASSEMBLY, "Decompressing assembly '{}' from the assembly store", name); auto header = reinterpret_cast(e.image_data); if (header->magic == COMPRESSED_DATA_MAGIC) { if (compressed_assemblies.descriptors == nullptr) [[unlikely]] { @@ -110,6 +111,7 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co } else #endif // def HAVE_LZ4 && def RELEASE { + log_debug (LOG_ASSEMBLY, "Assembly '{}' is not compressed in the assembly store", name); set_assembly_data_and_size (e.image_data, e.descriptor->data_size, assembly_data, assembly_data_size); } diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index e68a4d3ec11..538344d0186 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -31,7 +31,7 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size bool Host::clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept { // TODO: `path` might be a full path, make sure it isn't - log_debug (LOG_DEFAULT, "clr_bundle_probe (\"{}\"...)", path); + log_debug (LOG_DEFAULT, "clr_external_assembly_probe (\"{}\"...)", path); if (data_start == nullptr || size == nullptr) { return false; // TODO: abort instead? } diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 1e8f6517686..c167db2d095 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -57,9 +57,9 @@ namespace xamarin::android { .size = sizeof(host_runtime_contract), .context = nullptr, .get_runtime_property = clr_get_runtime_property, - .external_assembly_probe = clr_external_assembly_probe, .bundle_probe = nullptr, .pinvoke_override = clr_pinvoke_override, + .external_assembly_probe = clr_external_assembly_probe, }; // Enough to fit 0xffffffffffffffff + terminating NUL From 6e1c6c36c4185d13b966eced45cc513dbfb2ecdb Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 25 Feb 2025 00:16:08 +0100 Subject: [PATCH 126/143] Cleanup --- Configuration.props | 5 - Makefile | 5 - .../xaprepare/Application/KnownProperties.cs | 1 - .../Application/Properties.Defaults.cs.in | 1 - .../xaprepare/ConfigAndData/Configurables.cs | 5 - .../xaprepare/xaprepare/xaprepare.targets | 1 - .../Tasks/MaybeUseLocalClr.cs | 149 ------------------ .../Tasks/ResolveSdksTask.cs | 1 - .../java/mono/android/MonoPackageManager.java | 4 +- src/native/clr/runtime-base/android-system.cc | 4 +- 10 files changed, 4 insertions(+), 172 deletions(-) delete mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs diff --git a/Configuration.props b/Configuration.props index 00a9f676305..07a4740807e 100644 --- a/Configuration.props +++ b/Configuration.props @@ -220,9 +220,4 @@ - - - - <_LocalClrDirectory Condition=" Exists('$(AndroidToolchainDirectory)\clr') ">$(AndroidToolchainDirectory)\clr - diff --git a/Makefile b/Makefile index 12b7b25434b..85a0a28b92a 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,6 @@ PREPARE_SCENARIO = PREPARE_CI_PR ?= 0 PREPARE_CI ?= 0 PREPARE_AUTOPROVISION ?= 0 -LOCAL_CLR ?= _PREPARE_CI_MODE_PR_ARGS = --no-emoji --run-mode=CI _PREPARE_CI_MODE_ARGS = $(_PREPARE_CI_MODE_PR_ARGS) -a @@ -66,10 +65,6 @@ ifeq ($(XA_FORCE_COMPONENT_REFRESH),true) _PREPARE_ARGS += -refresh endif -ifneq ($(LOCAL_CLR),) -_PREPARE_ARGS += -p:_LocalClrDirectory="$(LOCAL_CLR)" -endif - _PREPARE_ARGS += $(PREPARE_ARGS) include build-tools/scripts/msbuild.mk diff --git a/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs b/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs index 4970148f1b6..2d9fd7efcfa 100644 --- a/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs +++ b/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs @@ -39,7 +39,6 @@ static class KnownProperties public const string JavaSdkDirectory = "JavaSdkDirectory"; public const string JdkIncludePath = "JdkIncludePath"; public const string LibZipSourceFullPath = "LibZipSourceFullPath"; - public const string LocalClrDirectory = "_LocalClrDirectory"; public const string ManagedRuntime = "ManagedRuntime"; public const string MicrosoftAndroidSdkOutDir = "MicrosoftAndroidSdkOutDir"; public const string MonoCecilVersion = "MonoCecilVersion"; diff --git a/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in b/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in index 12da7a9940e..6e59af3ab6e 100644 --- a/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in +++ b/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in @@ -43,7 +43,6 @@ namespace Xamarin.Android.Prepare properties.Add (KnownProperties.JavaSdkDirectory, StripQuotes (@"@JavaSdkDirectory@")); properties.Add (KnownProperties.JdkIncludePath, StripQuotes (@"@JdkIncludePath@")); properties.Add (KnownProperties.LibZipSourceFullPath, StripQuotes (@"@LibZipSourceFullPath@")); - properties.Add (KnownProperties.LocalClrDirectory, StripQuotes (@"@_LocalClrDirectory@")); properties.Add (KnownProperties.ManagedRuntime, StripQuotes (@"@ManagedRuntime@")); properties.Add (KnownProperties.MicrosoftAndroidSdkOutDir, StripQuotes (@"@MicrosoftAndroidSdkOutDir@")); properties.Add (KnownProperties.MonoCecilVersion, StripQuotes ("@MonoCecilVersion@")); diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 34deedc61d5..1d6d9dc8a61 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -250,11 +250,6 @@ static string GetNetcoreAppRuntimePath (Context ctx, string androidTarget) static string GetCoreClrAppRuntimePath (Context ctx, string androidTarget) { - string? localClrDir = ctx.Properties.GetValue (KnownProperties.LocalClrDirectory); - if (!String.IsNullOrEmpty (localClrDir)) { - return Path.Combine (localClrDir, "runtimes", $"android-{androidTarget}"); - } - // TODO: The nuget id and the ref package version are guesses atm, since the CoreCLR packages don't exist yet Log.Instance.Todo ("The nuget id and the ref package version are guesses atm, since the CoreCLR packages don't exist yet"); return Path.Combine ( diff --git a/build-tools/xaprepare/xaprepare/xaprepare.targets b/build-tools/xaprepare/xaprepare/xaprepare.targets index b0f428d4c7b..4c8e3be8906 100644 --- a/build-tools/xaprepare/xaprepare/xaprepare.targets +++ b/build-tools/xaprepare/xaprepare/xaprepare.targets @@ -76,7 +76,6 @@ - diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs deleted file mode 100644 index f9e1a4c4ece..00000000000 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MaybeUseLocalClr.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using Microsoft.Android.Build.Tasks; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Xamarin.Android.Tools; - -namespace Xamarin.Android.Tasks; - -// -// Optionally replaces all the CoreCLR items with corresponding ones found in a local -// directory, instead of a nuget. This is used whenever a developer wants to quickly -// iterate over changes to CoreCLR without publishing packages. -// -public class MaybeUseLocalCLR : AndroidTask -{ - public override string TaskPrefix => "MULC"; - - public string LocalClrDirectory { get; set; } = String.Empty; - - [Required] - public ITaskItem[] ResolvedFilesToPublish { get; set; } - - [Required] - public string AndroidRuntime { get; set; } = String.Empty; - - [Output] - public ITaskItem[] ResolvedFilesToAdd { get; set; } - - [Output] - public ITaskItem[] ResolvedFilesToIgnore { get; set; } - - public override bool RunTask () - { - if (String.Compare ("CoreCLR", AndroidRuntime, StringComparison.OrdinalIgnoreCase) != 0) { - Log.LogDebugMessage ("Not considering custom CLR runtime since target runtime is not CoreCLR."); - return true; - } - - if (String.IsNullOrEmpty (LocalClrDirectory)) { - Log.LogDebugMessage ("Local CLR directory not specified, will not use custom CLR runtime."); - return true; - } - - if (!Directory.Exists (LocalClrDirectory)) { - Log.LogWarning ($"Local CLR directory not found: ${LocalClrDirectory}"); - return true; - } - - var itemsToRemove = new List (); - var requiredClrItems = new List (); - var supportedArchitectures = new HashSet (); - foreach (ITaskItem lib in ResolvedFilesToPublish) { - ProcessItem (lib, itemsToRemove, requiredClrItems, supportedArchitectures); - } - - var itemsToAdd = new List (); - foreach (ITaskItem required in requiredClrItems) { - MakeLocalPackItem (required, itemsToAdd, supportedArchitectures); - } - - ResolvedFilesToAdd = itemsToAdd.ToArray (); - ResolvedFilesToIgnore = itemsToRemove.ToArray (); - return !Log.HasLoggedErrors; - } - - bool IsNativeAsset (ITaskItem item) - { - string? assetType = item.GetMetadata ("AssetType"); - if (String.IsNullOrEmpty (assetType)) { - return false; - } - - // System.Private.CoreLib.dll is an exception - it has `AssetType` set to `runtime`, but it's actually in the `native` - // portion of the runtime pack. - if (String.Compare ("System.Private.CoreLib.dll", Path.GetFileName (item.ItemSpec), StringComparison.OrdinalIgnoreCase) == 0) { - return true; - } - - return String.Compare (assetType, "native", StringComparison.OrdinalIgnoreCase) == 0; - } - - void MakeLocalPackItem (ITaskItem required, List itemsToAdd, HashSet supportedArchitectures) - { - foreach (AndroidTargetArch arch in MonoAndroidHelper.SupportedTargetArchitectures) { - if (!supportedArchitectures.Contains (arch)) { - continue; - } - - string rid = MonoAndroidHelper.ArchToRid (arch); - string fileName = Path.GetFileName (required.ItemSpec); - string basePath = Path.Combine (LocalClrDirectory, "runtimes", rid); - string filePath; - - if (IsNativeAsset (required)) { - filePath = Path.Combine (basePath, "native", fileName); - } else { - // TODO: don't hardcode framework name (`net10.0`), figure out how to compute it - filePath = Path.Combine (basePath, "lib", "net10.0", fileName); - } - - if (!File.Exists (filePath)) { - Log.LogWarning ($"Local CoreCLR pack file '{filePath}' does not exist."); - continue; - } - - var item = new TaskItem (filePath); - required.CopyMetadataTo (item); - item.SetMetadata ("NuGetPackageId", $"Local.App.Runtime.CoreCLR.{rid}"); - item.SetMetadata ("NuGetPackageVersion", "0.0.0.0"); - - Log.LogDebugMessage ($"Creating local CoreCLR runtime package item: {item}"); - itemsToAdd.Add (item); - } - } - - void ProcessItem (ITaskItem item, List itemsToRemove, List requiredClrItems, HashSet supportedArchitectures) - { - if (CoreClrItem (item, itemsToRemove, requiredClrItems)) { - return; - } - - string? rid = item.GetMetadata ("RuntimeIdentifier"); - if (String.IsNullOrEmpty (rid)) { - return; - } - - supportedArchitectures.Add (MonoAndroidHelper.RidToArch (rid)); - } - - bool CoreClrItem (ITaskItem item, List itemsToRemove, List requiredClrItems) - { - string? nugetId = item.GetMetadata ("NuGetPackageId"); - if (String.IsNullOrEmpty (nugetId)) { - return false; - } - - const string BionicNugetIdPrefix = "Microsoft.NETCore.App.Runtime.android-"; - if (!nugetId.StartsWith (BionicNugetIdPrefix, StringComparison.OrdinalIgnoreCase)) { - return false; - } - - itemsToRemove.Add (item); - requiredClrItems.Add (item); - return true; - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs index e2af82a63e2..499f79625f8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveSdksTask.cs @@ -30,7 +30,6 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using System; -using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Android.Build.Tasks; diff --git a/src/java-runtime/java/mono/android/MonoPackageManager.java b/src/java-runtime/java/mono/android/MonoPackageManager.java index 273612cd957..db90e2092ef 100644 --- a/src/java-runtime/java/mono/android/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/MonoPackageManager.java @@ -27,7 +27,6 @@ public class MonoPackageManager { public static void LoadApplication (Context context) { - Log.w ("XAMONO", "MonoPackageManager.LoadApplication: start"); synchronized (lock) { android.content.pm.ApplicationInfo runtimePackage = context.getApplicationInfo (); String[] apks = null; @@ -66,7 +65,8 @@ public static void LoadApplication (Context context) } // - // Should the order change here, src/native/runtime-base/shared-constants.hh must be updated accordingly + // Should the order change here, src/mono/native/runtime-base/shared-constants.hh and + // src/native/clr/include/constants.hh must be updated accordingly // String[] appDirs = new String[] {filesDir, cacheDir, dataDir}; boolean haveSplitApks = runtimePackage.splitSourceDirs != null && runtimePackage.splitSourceDirs.length > 0; diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index 2915b0fbcdc..cd3a15d4495 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -241,9 +241,9 @@ AndroidSystem::setup_environment () noexcept var_value = ""; } -// if constexpr (Constants::is_debug_build) { + if constexpr (Constants::is_debug_build) { log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); -// } + } if (setenv (var_name, var_value, 1) < 0) { log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); From 04d417070083cc9be8195a99a08fa73963324c90 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 25 Feb 2025 12:10:40 +0100 Subject: [PATCH 127/143] Updates to work with the latest dotnet/runtime changes --- CLR-Host-Notes.md | 45 ----- Configuration.props | 11 ++ .../xaprepare/ConfigAndData/Configurables.cs | 4 +- src-ThirdParty/dotnet/runtime/README | 11 ++ src-ThirdParty/dotnet/runtime/coreclrhost.h | 158 ++++++++++++++++++ .../dotnet/runtime/host_runtime_contract.h | 63 +++++++ src/native/CMakeLists.txt | 7 +- src/native/clr/host/host.cc | 2 +- src/native/clr/include/host/host.hh | 2 +- src/native/clr/include/xamarin-app.hh | 1 - src/native/native.targets | 4 +- 11 files changed, 254 insertions(+), 54 deletions(-) create mode 100644 src-ThirdParty/dotnet/runtime/README create mode 100644 src-ThirdParty/dotnet/runtime/coreclrhost.h create mode 100644 src-ThirdParty/dotnet/runtime/host_runtime_contract.h diff --git a/CLR-Host-Notes.md b/CLR-Host-Notes.md index f1db14ed2e0..325fa4e7e48 100644 --- a/CLR-Host-Notes.md +++ b/CLR-Host-Notes.md @@ -40,48 +40,3 @@ Being part of the contract, the target platform could implement process terminat ## Issues and workarounds -### Trimmer issue (as of 14.02.2025) - -https://github.com/dotnet/runtime/issues/112559 - -It appears the trimmer removes a bit too much at this point. In order to make the application run with trimming, one -needs to add the following to their .csproj (solution provided by Ivan Povazan): - -```xml - - - -``` - -and put the following in the `MyRoots.xml` file: - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` diff --git a/Configuration.props b/Configuration.props index 07a4740807e..2b4f189b5e5 100644 --- a/Configuration.props +++ b/Configuration.props @@ -220,4 +220,15 @@ + + diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 1d6d9dc8a61..9f49fb1e87b 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -250,11 +250,9 @@ static string GetNetcoreAppRuntimePath (Context ctx, string androidTarget) static string GetCoreClrAppRuntimePath (Context ctx, string androidTarget) { - // TODO: The nuget id and the ref package version are guesses atm, since the CoreCLR packages don't exist yet - Log.Instance.Todo ("The nuget id and the ref package version are guesses atm, since the CoreCLR packages don't exist yet"); return Path.Combine ( XAPackagesDir, - $"microsoft.netcore.app.runtime.coreclr.android-{androidTarget}", + $"microsoft.netcore.app.runtime.android-{androidTarget}", ctx.Properties.GetRequiredValue (KnownProperties.MicrosoftNETCoreAppRefPackageVersion), "runtimes", $"android-{androidTarget}" diff --git a/src-ThirdParty/dotnet/runtime/README b/src-ThirdParty/dotnet/runtime/README new file mode 100644 index 00000000000..c84cccac88f --- /dev/null +++ b/src-ThirdParty/dotnet/runtime/README @@ -0,0 +1,11 @@ +The header files in this directory are verbatim copies taken from the +https://github.com/dotnet/runtime/ repository. + +They can be found in the following locations in the repository: + + src/native/corehost/host_runtime_contract.h + src/coreclr/hosts/inc/coreclrhost.h + +and they MUST be in sync with the current version of the runtime being +used. They don't have to come from the same version, but their content +must be ABI and API compatible with it. diff --git a/src-ThirdParty/dotnet/runtime/coreclrhost.h b/src-ThirdParty/dotnet/runtime/coreclrhost.h new file mode 100644 index 00000000000..12099870c97 --- /dev/null +++ b/src-ThirdParty/dotnet/runtime/coreclrhost.h @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// +// APIs for hosting CoreCLR +// + +#ifndef __CORECLR_HOST_H__ +#define __CORECLR_HOST_H__ + +#if defined(_WIN32) && defined(_M_IX86) +#define CORECLR_CALLING_CONVENTION __stdcall +#else +#define CORECLR_CALLING_CONVENTION +#endif + +#include + +#ifdef __cplusplus +#define CORECLR_HOSTING_API_LINKAGE extern "C" +#else +#define CORECLR_HOSTING_API_LINKAGE +#endif + +// For each hosting API, we define a function prototype and a function pointer +// The prototype is useful for implicit linking against the dynamic coreclr +// library and the pointer for explicit dynamic loading (dlopen, LoadLibrary) +#define CORECLR_HOSTING_API(function, ...) \ + CORECLR_HOSTING_API_LINKAGE int CORECLR_CALLING_CONVENTION function(__VA_ARGS__); \ + typedef int (CORECLR_CALLING_CONVENTION *function##_ptr)(__VA_ARGS__) + +// +// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain +// +// Parameters: +// exePath - Absolute path of the executable that invoked the ExecuteAssembly (the native host application) +// appDomainFriendlyName - Friendly name of the app domain that will be created to execute the assembly +// propertyCount - Number of properties (elements of the following two arguments) +// propertyKeys - Keys of properties of the app domain +// propertyValues - Values of properties of the app domain +// hostHandle - Output parameter, handle of the created host +// domainId - Output parameter, id of the created app domain +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_initialize, + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + +// +// Type of the callback function that can be set by the coreclr_set_error_writer +// +typedef void (*coreclr_error_writer_callback_fn) (const char *message); + +// +// Set callback for writing error logging +// +// Parameters: +// errorWriter - callback that will be called for each line of the error info +// - passing in NULL removes a callback that was previously set +// +// Returns: +// S_OK +// +CORECLR_HOSTING_API(coreclr_set_error_writer, + coreclr_error_writer_callback_fn errorWriter); + +// +// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_shutdown, + void* hostHandle, + unsigned int domainId); + +// +// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// latchedExitCode - Latched exit code after domain unloaded +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_shutdown_2, + void* hostHandle, + unsigned int domainId, + int* latchedExitCode); + +// +// Create a native callable function pointer for a managed method. +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// entryPointAssemblyName - Name of the assembly which holds the custom entry point +// entryPointTypeName - Name of the type which holds the custom entry point +// entryPointMethodName - Name of the method which is the custom entry point +// delegate - Output parameter, the function stores a native callable function pointer to the delegate at the specified address +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_create_delegate, + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); + +// +// Execute a managed assembly with given arguments +// +// Parameters: +// hostHandle - Handle of the host +// domainId - Id of the domain +// argc - Number of arguments passed to the executed assembly +// argv - Array of arguments passed to the executed assembly +// managedAssemblyPath - Path of the managed assembly to execute (or NULL if using a custom entrypoint). +// exitCode - Exit code returned by the executed assembly +// +// Returns: +// HRESULT indicating status of the operation. S_OK if the assembly was successfully executed +// +CORECLR_HOSTING_API(coreclr_execute_assembly, + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); + +#undef CORECLR_HOSTING_API + +// +// Callback types used by the hosts +// +typedef bool(CORECLR_CALLING_CONVENTION ExternalAssemblyProbeFn)(const char* path, void** data_start, int64_t* size); +typedef bool(CORECLR_CALLING_CONVENTION BundleProbeFn)(const char* path, int64_t* offset, int64_t* size, int64_t* compressedSize); +typedef const void* (CORECLR_CALLING_CONVENTION PInvokeOverrideFn)(const char* libraryName, const char* entrypointName); + + +#endif // __CORECLR_HOST_H__ diff --git a/src-ThirdParty/dotnet/runtime/host_runtime_contract.h b/src-ThirdParty/dotnet/runtime/host_runtime_contract.h new file mode 100644 index 00000000000..9d03c52cf24 --- /dev/null +++ b/src-ThirdParty/dotnet/runtime/host_runtime_contract.h @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __HOST_RUNTIME_CONTRACT_H__ +#define __HOST_RUNTIME_CONTRACT_H__ + +#include +#include + +#if defined(_WIN32) + #define HOST_CONTRACT_CALLTYPE __stdcall +#else + #define HOST_CONTRACT_CALLTYPE +#endif + +// Known host property names +#define HOST_PROPERTY_RUNTIME_CONTRACT "HOST_RUNTIME_CONTRACT" +#define HOST_PROPERTY_APP_PATHS "APP_PATHS" +#define HOST_PROPERTY_BUNDLE_PROBE "BUNDLE_PROBE" +#define HOST_PROPERTY_ENTRY_ASSEMBLY_NAME "ENTRY_ASSEMBLY_NAME" +#define HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES "NATIVE_DLL_SEARCH_DIRECTORIES" +#define HOST_PROPERTY_PINVOKE_OVERRIDE "PINVOKE_OVERRIDE" +#define HOST_PROPERTY_PLATFORM_RESOURCE_ROOTS "PLATFORM_RESOURCE_ROOTS" +#define HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES "TRUSTED_PLATFORM_ASSEMBLIES" + +struct host_runtime_contract +{ + size_t size; + + // Context for the contract. Pass to functions taking a contract context. + void* context; + + // Get the value of a runtime property. + // Returns the length of the property including a terminating null or -1 if not found. + size_t(HOST_CONTRACT_CALLTYPE* get_runtime_property)( + const char* key, + /*out*/ char* value_buffer, + size_t value_buffer_size, + void* contract_context); + + // Probe an app bundle for `path`. Sets its location (`offset`, `size`) in the bundle if found. + // Returns true if found, false otherwise. If false, out parameter values are ignored by the runtime. + bool(HOST_CONTRACT_CALLTYPE* bundle_probe)( + const char* path, + /*out*/ int64_t* offset, + /*out*/ int64_t* size, + /*out*/ int64_t* compressedSize); + + // Get the function overriding the specified p/invoke (`library_name`, `entry_point_name`). + // Returns a pointer to the function if the p/invoke is overridden, nullptr otherwise. + const void* (HOST_CONTRACT_CALLTYPE* pinvoke_override)( + const char* library_name, + const char* entry_point_name); + + // Probe the host for `path`. Sets pointer to data start and its size, if found. + // Returns true if found, false otherwise. If false, out parameter values are ignored by the runtime. + bool(HOST_CONTRACT_CALLTYPE* external_assembly_probe)( + const char* path, + /*out*/ void **data_start, + /*out*/ int64_t* size); +}; + +#endif // __HOST_RUNTIME_CONTRACT_H__ diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index a1cee1367a6..d1b7fb40695 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -213,7 +213,12 @@ if(IS_MONO_RUNTIME) else() # TEMPORARY: for now JI needs to build with MonoVM embedding APIs set(TEMP_MONO_RUNTIME_INCLUDE_DIR ${TEMP_NETCORE_NET_RUNTIME_DIR}/native/include/mono-2.0) - set(RUNTIME_INCLUDE_DIR ${NET_RUNTIME_DIR}/native/include/clr) + + if(LOCAL_CORECLR_PATH) + set(RUNTIME_INCLUDE_DIR ${LOCAL_CORECLR_PATH}/src/native/corehost) + else() + set(RUNTIME_INCLUDE_DIR ${REPO_ROOT_DIR}/src-ThirdParty/dotnet/runtime) + endif() endif() set(JAVA_INTEROP_INCLUDE_DIR ${JAVA_INTEROP_SRC_PATH}) diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 538344d0186..02e26cb5541 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -1,6 +1,6 @@ #include -#include +#include #include #include diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index c167db2d095..a1e70ca8135 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include "../runtime-base/timing.hh" diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index 41b82d3ff2d..d2a7899dfe5 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -5,7 +5,6 @@ #include #include -#include #include diff --git a/src/native/native.targets b/src/native/native.targets index 6b997259f4a..a7825885943 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -112,8 +112,8 @@ <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF - - <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) "$(MSBuildThisFileDirectory)" + <_LocalDotNetRuntimePath Condition=" '$(CLRLocalRuntimePath)' != '' And '$(CMakeRuntimeFlavor)' == 'CoreCLR' ">-DLOCAL_CORECLR_PATH="$(CLRLocalRuntimePath)" + <_CmakeAndroidFlags>-DOUTPUT_PATH="$(OutputPath.TrimEnd('\'))" -DRUNTIME_FLAVOR="$(CMakeRuntimeFlavor)" $(_NoInline) $(_NoStrip) $(_LocalDotNetRuntimePath) "$(MSBuildThisFileDirectory)" From b835667fa8f177a96beb54eebd4de726a19bb162 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 25 Feb 2025 13:17:08 +0100 Subject: [PATCH 128/143] Make build using local CLR work --- src/native/CMakeLists.txt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index d1b7fb40695..3c71fcf8580 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -155,10 +155,17 @@ include("${XA_BUILD_DIR}/xa_build_configuration.cmake") # Paths # if(IS_CLR_RUNTIME) - set(RUNTIME_DIR_ARM64 "${CORECLR_APP_RUNTIME_DIR_ARM64}") - set(RUNTIME_DIR_ARM "${CORECLR_APP_RUNTIME_DIR_ARM}") - set(RUNTIME_DIR_X86_64 "${CORECLR_APP_RUNTIME_DIR_X86_64}") - set(RUNTIME_DIR_X86 "${CORECLR_APP_RUNTIME_DIR_X86}") + if(LOCAL_CORECLR_PATH) + set(RUNTIME_DIR_ARM64 "${LOCAL_CORECLR_PATH}/runtimes/android-arm64") + set(RUNTIME_DIR_ARM "${LOCAL_CORECLR_PATH}/runtimes/android-arm") + set(RUNTIME_DIR_X86_64 "${LOCAL_CORECLR_PATH}/runtimes/android-x64") + set(RUNTIME_DIR_X86 "${LOCAL_CORECLR_PATH}/runtimes/android-x86") + else() + set(RUNTIME_DIR_ARM64 "${CORECLR_APP_RUNTIME_DIR_ARM64}") + set(RUNTIME_DIR_ARM "${CORECLR_APP_RUNTIME_DIR_ARM}") + set(RUNTIME_DIR_X86_64 "${CORECLR_APP_RUNTIME_DIR_X86_64}") + set(RUNTIME_DIR_X86 "${CORECLR_APP_RUNTIME_DIR_X86}") + endif() # TEMPORARY: for now JI needs to build with MonoVM embedding APIs set(TEMP_NETCORE_RUNTIME_DIR_ARM64 "${NETCORE_APP_RUNTIME_DIR_ARM64}") @@ -215,7 +222,8 @@ else() set(TEMP_MONO_RUNTIME_INCLUDE_DIR ${TEMP_NETCORE_NET_RUNTIME_DIR}/native/include/mono-2.0) if(LOCAL_CORECLR_PATH) - set(RUNTIME_INCLUDE_DIR ${LOCAL_CORECLR_PATH}/src/native/corehost) + set(CLR_REPO_ROOT_PATH "${LOCAL_CORECLR_PATH}/../../../..") + set(RUNTIME_INCLUDE_DIR "${CLR_REPO_ROOT_PATH}/src/native/corehost;${CLR_REPO_ROOT_PATH}/src/coreclr/hosts/inc") else() set(RUNTIME_INCLUDE_DIR ${REPO_ROOT_DIR}/src-ThirdParty/dotnet/runtime) endif() From 8d4e35ca47e3c6b7dcd39dcaa99c3330f39d92b0 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 25 Feb 2025 18:48:50 +0100 Subject: [PATCH 129/143] Fix after rebase From 7ea447d797e4a49c141c286cadc8dfffad41023d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 25 Feb 2025 20:16:26 +0100 Subject: [PATCH 130/143] No-compression MAUI hack --- .../Tasks/GenerateJavaStubs.cs | 1 - src/native/clr/host/assembly-store.cc | 18 ++++++++++++++---- src/native/clr/include/host/assembly-store.hh | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 6209a8577b2..80879a28eea 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -271,7 +271,6 @@ internal static Dictionary MaybeGetArchAssemblies (Dictionary Files.CopyIfStringChanged (contents, real_provider); } - // For NativeAOT, generate JavaInteropRuntime.java if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) { const string fileName = "JavaInteropRuntime.java"; diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc index 661ad16ab4d..75ca4471dfd 100644 --- a/src/native/clr/host/assembly-store.cc +++ b/src/native/clr/host/assembly-store.cc @@ -20,15 +20,15 @@ void AssemblyStore::set_assembly_data_and_size (uint8_t* source_assembly_data, u } [[gnu::always_inline]] -auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name) noexcept -> std::tuple +auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name, bool force_rw) noexcept -> std::tuple { uint8_t *assembly_data = nullptr; uint32_t assembly_data_size = 0; #if defined (HAVE_LZ4) && defined (RELEASE) - log_debug (LOG_ASSEMBLY, "Decompressing assembly '{}' from the assembly store", name); auto header = reinterpret_cast(e.image_data); if (header->magic == COMPRESSED_DATA_MAGIC) { + log_debug (LOG_ASSEMBLY, "Decompressing assembly '{}' from the assembly store", name); if (compressed_assemblies.descriptors == nullptr) [[unlikely]] { Helpers::abort_application (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined"sv); } @@ -112,7 +112,16 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co #endif // def HAVE_LZ4 && def RELEASE { log_debug (LOG_ASSEMBLY, "Assembly '{}' is not compressed in the assembly store", name); - set_assembly_data_and_size (e.image_data, e.descriptor->data_size, assembly_data, assembly_data_size); + + // HACK! START + // Currently, MAUI crashes when we return a pointer to read-only data, so we must copy + // the assembly data to a read-write area. + log_debug (LOG_ASSEMBLY, "Copying assembly data to an r/w memory area"); + uint8_t *rw_pointer = static_cast(malloc (e.descriptor->data_size)); + memcpy (rw_pointer, e.image_data, e.descriptor->data_size); + set_assembly_data_and_size (rw_pointer, e.descriptor->data_size, assembly_data, assembly_data_size); + // HACK! END + // set_assembly_data_and_size (e.image_data, e.descriptor->data_size, assembly_data, assembly_data_size); } return {assembly_data, assembly_data_size}; @@ -178,7 +187,8 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) ); } - auto [assembly_data, assembly_data_size] = get_assembly_data (assembly_runtime_info, name); + constexpr hash_t mscorlib_hash = 0x579a06fed6eec900; + auto [assembly_data, assembly_data_size] = get_assembly_data (assembly_runtime_info, name, name_hash == mscorlib_hash); size = assembly_data_size; return assembly_data; } diff --git a/src/native/clr/include/host/assembly-store.hh b/src/native/clr/include/host/assembly-store.hh index 033e7d3ce1c..4648231e958 100644 --- a/src/native/clr/include/host/assembly-store.hh +++ b/src/native/clr/include/host/assembly-store.hh @@ -25,7 +25,7 @@ namespace xamarin::android { static void set_assembly_data_and_size (uint8_t* source_assembly_data, uint32_t source_assembly_data_size, uint8_t*& dest_assembly_data, uint32_t& dest_assembly_data_size) noexcept; // Returns a tuple of - static auto get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name) noexcept -> std::tuple; + static auto get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, std::string_view const& name, bool force_rw = false) noexcept -> std::tuple; static auto find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept -> const AssemblyStoreIndexEntry*; private: From ce4e59553d14c0b71581cd247c9ddb3ad3828770 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 26 Feb 2025 16:10:06 +0100 Subject: [PATCH 131/143] Disable native build until up-to-date runtime packs are available --- Xamarin.Android.sln | 9 +-------- build-tools/xaprepare/xaprepare/package-download.proj | 2 ++ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index c24d1c97d51..9eb3895b885 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -45,7 +45,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Diagnost EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Cecil", "external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil.csproj", "{D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "native", "src\native\native-mono.csproj", "{53EE4C57-1C03-405A-8243-8DA539546C88}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "native-mono", "src\native\native-mono.csproj", "{53EE4C57-1C03-405A-8243-8DA539546C88}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}" EndProject @@ -125,8 +125,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Sdk.Analy EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proguard-android", "src\proguard-android\proguard-android.csproj", "{5FD0133B-69E5-4474-9B67-9FD1D0150C70}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "native-clr", "src\native\native-clr.csproj", "{39F49484-872A-489D-8E6B-3BC532DD571D}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Runtime.NativeAOT", "src\Microsoft.Android.Runtime.NativeAOT\Microsoft.Android.Runtime.NativeAOT.csproj", "{E8831F32-11D7-D42C-E43C-711998BC357A}" EndProject Global @@ -351,10 +349,6 @@ Global {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Debug|AnyCPU.Build.0 = Debug|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.ActiveCfg = Release|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.Build.0 = Release|Any CPU - {39F49484-872A-489D-8E6B-3BC532DD571D}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU - {39F49484-872A-489D-8E6B-3BC532DD571D}.Debug|AnyCPU.Build.0 = Debug|Any CPU - {39F49484-872A-489D-8E6B-3BC532DD571D}.Release|AnyCPU.ActiveCfg = Release|Any CPU - {39F49484-872A-489D-8E6B-3BC532DD571D}.Release|AnyCPU.Build.0 = Release|Any CPU {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.Build.0 = Debug|Any CPU {E8831F32-11D7-D42C-E43C-711998BC357A}.Release|AnyCPU.ActiveCfg = Release|Any CPU @@ -418,7 +412,6 @@ Global {A39B6D7C-6616-40D6-8AE4-C6CEE93D2708} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {5E806C9F-1B67-4B6B-A6AB-258834250DBB} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} {5FD0133B-69E5-4474-9B67-9FD1D0150C70} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} - {39F49484-872A-489D-8E6B-3BC532DD571D} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} {E8831F32-11D7-D42C-E43C-711998BC357A} = {04E3E11E-B47D-4599-8AFC-50515A95E715} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/build-tools/xaprepare/xaprepare/package-download.proj b/build-tools/xaprepare/xaprepare/package-download.proj index f68692ad0b9..6f8053660df 100644 --- a/build-tools/xaprepare/xaprepare/package-download.proj +++ b/build-tools/xaprepare/xaprepare/package-download.proj @@ -20,6 +20,8 @@ Otherwise, $(MicrosoftNETCoreAppRefPackageVersion) from eng/Versions.props will + + From d4cc649187b97488119c29452701a7f288b68fe3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 26 Feb 2025 17:48:30 +0100 Subject: [PATCH 132/143] Let's see if this works --- src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 28a01bf23af..d9162c32028 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2242,7 +2242,7 @@ because xbuild doesn't support framework reference assemblies. Date: Wed, 26 Feb 2025 20:04:52 +0100 Subject: [PATCH 133/143] FastDev needs the parameters too --- .../Xamarin.Android.Common.targets | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index d9162c32028..291999c74e3 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2363,11 +2363,14 @@ because xbuild doesn't support framework reference assemblies. + + SupportedAbis="@(_BuildTargetAbis)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> @@ -2383,7 +2386,8 @@ because xbuild doesn't support framework reference assemblies. IncludeWrapSh="$(AndroidIncludeWrapSh)" CheckedBuild="$(_AndroidCheckedBuild)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - IntermediateOutputPath="$(IntermediateOutputPath)"> + IntermediateOutputPath="$(IntermediateOutputPath)" + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> From f19135a5bcc6ca238d8a1dc774c7934b26f837e7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 26 Feb 2025 20:13:36 +0100 Subject: [PATCH 134/143] Fix after rebase --- .../Tasks/GenerateJavaStubs.cs | 104 +----------------- 1 file changed, 3 insertions(+), 101 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 80879a28eea..5beba41c2cc 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -74,9 +74,6 @@ public class GenerateJavaStubs : AndroidTask public string CodeGenerationTarget { get; set; } = ""; - [Required] - public string TargetName { get; set; } = ""; - AndroidRuntime androidRuntime; JavaPeerStyle codeGenerationTarget; @@ -251,106 +248,11 @@ void Run (bool useMarshalMethods) internal static Dictionary MaybeGetArchAssemblies (Dictionary> dict, AndroidTargetArch arch) { - // Create additional runtime provider java sources. - bool isMonoVM = androidRuntime switch { - Xamarin.Android.Tasks.AndroidRuntime.MonoVM => true, - Xamarin.Android.Tasks.AndroidRuntime.CoreCLR => true, - _ => false, - }; - - string providerTemplateFile = isMonoVM ? - "MonoRuntimeProvider.Bundled.java" : - "NativeAotRuntimeProvider.java"; - string providerTemplate = GetResource (providerTemplateFile); - - foreach (var provider in additionalProviders) { - var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); - var real_provider = isMonoVM ? - Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : - Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); - Files.CopyIfStringChanged (contents, real_provider); - } - - // For NativeAOT, generate JavaInteropRuntime.java - if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) { - const string fileName = "JavaInteropRuntime.java"; - string template = GetResource (fileName); - var contents = template.Replace ("@MAIN_ASSEMBLY_NAME@", TargetName); - var path = Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", fileName); - Log.LogDebugMessage ($"Writing: {path}"); - Files.CopyIfStringChanged (contents, path); - } - - // Create additional application java sources. - StringWriter regCallsWriter = new StringWriter (); - regCallsWriter.WriteLine ("// Application and Instrumentation ACWs must be registered first."); - foreach (TypeDefinition type in codeGenState.JavaTypesForJCW) { - if (JavaNativeTypeManager.IsApplication (type, codeGenState.TypeCache) || JavaNativeTypeManager.IsInstrumentation (type, codeGenState.TypeCache)) { - if (codeGenState.Classifier != null && !codeGenState.Classifier.FoundDynamicallyRegisteredMethods (type)) { - continue; - } - - string javaKey = JavaNativeTypeManager.ToJniName (type, codeGenState.TypeCache).Replace ('/', '.'); - regCallsWriter.WriteLine ( - codeGenerationTarget == JavaPeerStyle.XAJavaInterop1 ? - "\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);" : - "\t\tnet.dot.jni.ManagedPeer.registerNativeMembers ({1}.class, {1}.__md_methods);", - type.GetAssemblyQualifiedName (codeGenState.TypeCache), - javaKey - ); - } - } - regCallsWriter.Close (); - - var real_app_dir = Path.Combine (OutputDirectory, "src", "net", "dot", "android"); - string applicationTemplateFile = "ApplicationRegistration.java"; - SaveResource ( - applicationTemplateFile, - applicationTemplateFile, - real_app_dir, - template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ()) - ); - } - - IList MergeManifest (NativeCodeGenState codeGenState, Dictionary userAssemblies) - { - var manifest = new ManifestDocument (ManifestTemplate) { - PackageName = PackageName, - VersionName = VersionName, - ApplicationLabel = ApplicationLabel ?? PackageName, - Placeholders = ManifestPlaceholders, - Resolver = codeGenState.Resolver, - SdkDir = AndroidSdkDir, - TargetSdkVersion = AndroidSdkPlatform, - MinSdkVersion = MonoAndroidHelper.ConvertSupportedOSPlatformVersionToApiLevel (SupportedOSPlatformVersion).ToString (), - Debug = Debug, - MultiDex = MultiDex, - NeedsInternet = NeedsInternet, - AndroidRuntime = androidRuntime, - }; - // Only set manifest.VersionCode if there is no existing value in AndroidManifest.xml. - if (manifest.HasVersionCode) { - Log.LogDebugMessage ($"Using existing versionCode in: {ManifestTemplate}"); - } else if (!string.IsNullOrEmpty (VersionCode)) { - manifest.VersionCode = VersionCode; - } - manifest.Assemblies.AddRange (userAssemblies.Values.Select (item => item.ItemSpec)); - - if (!String.IsNullOrWhiteSpace (CheckedBuild)) { - // We don't validate CheckedBuild value here, this will be done in BuildApk. We just know that if it's - // on then we need android:debuggable=true and android:extractNativeLibs=true - manifest.ForceDebuggable = true; - manifest.ForceExtractNativeLibs = true; - } - - IList additionalProviders = manifest.Merge (Log, codeGenState.TypeCache, codeGenState.AllJavaTypes, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); - - // Only write the new manifest if it actually changed - if (manifest.SaveIfChanged (Log, MergedAndroidManifestOutput)) { - Log.LogDebugMessage ($"Saving: {MergedAndroidManifestOutput}"); + if (!dict.TryGetValue (arch, out Dictionary archDict)) { + return new Dictionary (StringComparer.OrdinalIgnoreCase); } - return additionalProviders; + return archDict; } (bool success, NativeCodeGenState? stubsState) GenerateJavaSourcesAndMaybeClassifyMarshalMethods (AndroidTargetArch arch, Dictionary assemblies, Dictionary userAssemblies, bool useMarshalMethods, bool generateJavaCode) From 0a11c7f88ae8e0f98da29d4725a8fb5f6ce999fb Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 26 Feb 2025 20:17:06 +0100 Subject: [PATCH 135/143] One more fixup --- .../Tasks/GenerateMainAndroidManifest.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs index 9603655aaf2..9e8f3e9ea94 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs @@ -136,23 +136,23 @@ IList MergeManifest (NativeCodeGenState codeGenState, Dictionary additionalProviders) { - if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { - // Create additional runtime provider java sources. - bool isMonoVM = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM; - string providerTemplateFile = isMonoVM ? - "MonoRuntimeProvider.Bundled.java" : - "NativeAotRuntimeProvider.java"; - string providerTemplate = GetResource (providerTemplateFile); - - foreach (var provider in additionalProviders) { - var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); - var real_provider = isMonoVM ? - Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : - Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); - Files.CopyIfStringChanged (contents, real_provider); - } - } else { - Log.LogDebugMessage ($"Skipping android.content.ContentProvider generation for: {androidRuntime}"); + // Create additional runtime provider java sources. + bool isMonoVM = androidRuntime switch { + Xamarin.Android.Tasks.AndroidRuntime.MonoVM => true, + Xamarin.Android.Tasks.AndroidRuntime.CoreCLR => true, + _ => false, + }; + string providerTemplateFile = isMonoVM ? + "MonoRuntimeProvider.Bundled.java" : + "NativeAotRuntimeProvider.java"; + string providerTemplate = GetResource (providerTemplateFile); + + foreach (var provider in additionalProviders) { + var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); + var real_provider = isMonoVM ? + Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : + Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); + Files.CopyIfStringChanged (contents, real_provider); } // For NativeAOT, generate JavaInteropRuntime.java From d5dec289127f01c2970528df31c9b600bbee591b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 27 Feb 2025 09:26:29 +0100 Subject: [PATCH 136/143] Revert "Bump to dotnet/sdk/main@d3d96bc671 10.0.100-preview.3.25126.7 (#9849)" This reverts commit dfa304657aa30b601da4f3b3827dfd43161e6a9a. Breaks MSBuild: MSBUILD : error MSB1025: An internal failure occurred while running MSBuild. Microsoft.Build.Framework.InternalErrorException: MSB0001: Internal MSBuild Error: Missing resource 'RestoreComplete' at Microsoft.Build.Shared.ErrorUtilities.ThrowInternalError(String message, Object[] args) at Microsoft.Build.Shared.ErrorUtilities.VerifyThrow(Boolean condition, String unformattedMessage, Object arg0) at Microsoft.Build.Shared.AssemblyResources.GetStringFromEngineResources(String name) at Microsoft.Build.Logging.TerminalLogger.ProjectFinished(Object sender, ProjectFinishedEventArgs e) at Microsoft.Build.BackEnd.Logging.EventSourceSink.RaiseEvent[TArgs](TArgs buildEvent, ArgsHandler`1 handler, ArgsHandler`1 followUpHandler) at Microsoft.Build.BackEnd.Logging.EventSourceSink.RaiseEvent[TArgs](TArgs buildEvent, ArgsHandler`1 handler, ArgsHandler`1 followUpHandler) at Microsoft.Build.BackEnd.Logging.LoggingService.RouteBuildEvent(BuildEventArgs eventArg) at Microsoft.Build.BackEnd.Logging.LoggingService.RouteBuildEvent(Object loggingEvent) at Microsoft.Build.BackEnd.Logging.LoggingService.LoggingEventProcessor(Object loggingEvent) --- eng/Version.Details.xml | 20 ++++++++++---------- eng/Versions.props | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ce142c8cbf1..95871c6bbba 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,24 +1,24 @@ - + https://github.com/dotnet/sdk - d3d96bc671022fd5388f652180d333201ac0cc2b + 856d3483ba4d2dab84fcf8e7db66fa8555c4c0ed - + https://github.com/dotnet/runtime - fa3beb9521adb450863f3460d0e71bc0c5498d02 + 457e3eb93e35f60f9b0515ee6a4b75e76a64ce8c - + https://github.com/dotnet/runtime - fa3beb9521adb450863f3460d0e71bc0c5498d02 + 457e3eb93e35f60f9b0515ee6a4b75e76a64ce8c - + https://github.com/dotnet/emsdk - 46e7f0e542981ed77988f2ec0d37c8da0dd7da0d + 34f1100060f0d618239c8e6d73d3e80862429598 - + https://github.com/dotnet/cecil - 864dffa259f3931b3d51dea0db54a2488ae455ba + dfa03011d6474bd0e6c9d0363e4f3b18b99f2ad8 diff --git a/eng/Versions.props b/eng/Versions.props index f61efce1370..de316d723e1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,16 +1,16 @@ - 10.0.100-preview.3.25126.7 + 10.0.100-preview.3.25122.1 $(MicrosoftNETSdkPackageVersion) - 10.0.0-preview.3.25125.16 - 10.0.0-preview.3.25125.16 + 10.0.0-preview.2.25119.7 + 10.0.0-preview.2.25119.7 7.0.0-beta.22103.1 10.0.0-beta.24476.2 - 10.0.0-preview.3.25124.1 + 10.0.0-preview.2.25117.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 7.0.100-rc.1.22410.7 - 0.11.5-alpha.25109.3 + 0.11.5-alpha.25078.1 $(MicrosoftNETCoreAppRefPackageVersion) 35.0.24 From 07edabcdd32349f45683654f371549e81927f87f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 27 Feb 2025 12:22:12 +0100 Subject: [PATCH 137/143] Temporarily disable a CoreCLR test and try to fix NativeAOT builds --- .../Tests/Xamarin.Android.Build.Tests/BuildTest2.cs | 5 ++++- .../Xamarin.Android.Common.targets | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 362ab093137..3d10afa3e33 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -108,6 +108,9 @@ public void BuildBasicApplication ([Values (true, false)] bool isRelease, [Value [Test] public void BasicApplicationOtherRuntime ([Values (true, false)] bool isRelease) { + // This test would fail, as it requires **our** updated runtime pack, which isn't currently created + // It is created in `src/native/native-clr.csproj` which isn't built atm. + Assert.Ignore ("CoreCLR support isn't fully enabled yet. This test will be enabled in a follow-up PR."); var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, // Add locally downloaded CoreCLR packs @@ -465,7 +468,7 @@ public void XA1037PropertyDeprecatedWarning (string property, string value, bool XamarinAndroidProject proj = isBindingProject ? new XamarinAndroidBindingProject () : new XamarinAndroidApplicationProject (); proj.IsRelease = isRelease; proj.SetProperty (property, value); - + using (ProjectBuilder b = isBindingProject ? CreateDllBuilder (Path.Combine ("temp", TestName)) : CreateApkBuilder (Path.Combine ("temp", TestName))) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); Assert.IsTrue (StringAssertEx.ContainsText (b.LastBuildOutput, $"The '{property}' MSBuild property is deprecated and will be removed"), diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 291999c74e3..06953e84d70 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1370,7 +1370,7 @@ because xbuild doesn't support framework reference assemblies. - + <_RuntimeJar>$(MSBuildThisFileDirectory)\java_runtime_net6.jar <_RuntimeDex>$(MSBuildThisFileDirectory)\java_runtime_net6.dex From 2122ecbd7b4e57e90c2a3ab012b52df2de36486b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 27 Feb 2025 14:04:03 +0100 Subject: [PATCH 138/143] Neither assembly store nor assemblies are used with NativeAOT --- src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 06953e84d70..d37b47e7c6f 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2204,6 +2204,7 @@ because xbuild doesn't support framework reference assemblies. in monodroid. --> Date: Thu, 27 Feb 2025 18:36:13 +0100 Subject: [PATCH 139/143] Reapply "Bump to dotnet/sdk/main@d3d96bc671 10.0.100-preview.3.25126.7 (#9849)" This reverts commit 2da70a5c4752c029c01137e76bb69115291d9176. --- eng/Version.Details.xml | 20 ++++++++++---------- eng/Versions.props | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 95871c6bbba..ce142c8cbf1 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,24 +1,24 @@ - + https://github.com/dotnet/sdk - 856d3483ba4d2dab84fcf8e7db66fa8555c4c0ed + d3d96bc671022fd5388f652180d333201ac0cc2b - + https://github.com/dotnet/runtime - 457e3eb93e35f60f9b0515ee6a4b75e76a64ce8c + fa3beb9521adb450863f3460d0e71bc0c5498d02 - + https://github.com/dotnet/runtime - 457e3eb93e35f60f9b0515ee6a4b75e76a64ce8c + fa3beb9521adb450863f3460d0e71bc0c5498d02 - + https://github.com/dotnet/emsdk - 34f1100060f0d618239c8e6d73d3e80862429598 + 46e7f0e542981ed77988f2ec0d37c8da0dd7da0d - + https://github.com/dotnet/cecil - dfa03011d6474bd0e6c9d0363e4f3b18b99f2ad8 + 864dffa259f3931b3d51dea0db54a2488ae455ba diff --git a/eng/Versions.props b/eng/Versions.props index de316d723e1..f61efce1370 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,16 +1,16 @@ - 10.0.100-preview.3.25122.1 + 10.0.100-preview.3.25126.7 $(MicrosoftNETSdkPackageVersion) - 10.0.0-preview.2.25119.7 - 10.0.0-preview.2.25119.7 + 10.0.0-preview.3.25125.16 + 10.0.0-preview.3.25125.16 7.0.0-beta.22103.1 10.0.0-beta.24476.2 - 10.0.0-preview.2.25117.1 + 10.0.0-preview.3.25124.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 7.0.100-rc.1.22410.7 - 0.11.5-alpha.25078.1 + 0.11.5-alpha.25109.3 $(MicrosoftNETCoreAppRefPackageVersion) 35.0.24 From 73d05886d9ed7aad7914dde0eccd691a2a0336e1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 27 Feb 2025 22:03:55 +0100 Subject: [PATCH 140/143] Let's try this --- .../targets/Microsoft.Android.Sdk.Aot.targets | 6 ++++++ .../Xamarin.Android.Common.targets | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 3e24b0d8c08..87bd8b402e8 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -77,6 +77,12 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). + + + + <_RuntimePackLibraryDirectory Include="$(_RuntimePackLibraryDirectoriesList)" /> + + + + <_RuntimePackLibraryDirectoriesList>@(_RuntimePackLibraryDirectory) + + From 8cc1f890f0052667e23b7004ec93041f2f7f3dab Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 28 Feb 2025 11:55:26 +0100 Subject: [PATCH 141/143] Revert "Let's try this" This reverts commit 73d05886d9ed7aad7914dde0eccd691a2a0336e1. Seems to break Aot --- .../targets/Microsoft.Android.Sdk.Aot.targets | 6 ------ .../Xamarin.Android.Common.targets | 5 ----- 2 files changed, 11 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 87bd8b402e8..3e24b0d8c08 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -77,12 +77,6 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). - - - - <_RuntimePackLibraryDirectory Include="$(_RuntimePackLibraryDirectoriesList)" /> - - - - <_RuntimePackLibraryDirectoriesList>@(_RuntimePackLibraryDirectory) - - From 473814d1afb410ce17131ba28972e10044c7d984 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 28 Feb 2025 13:07:05 +0100 Subject: [PATCH 142/143] Take two --- .../targets/Microsoft.Android.Sdk.Aot.targets | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 3e24b0d8c08..17d7009cc86 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -30,6 +30,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). + @@ -77,6 +78,17 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). + + + + + + + Date: Fri, 28 Feb 2025 09:25:20 -0500 Subject: [PATCH 143/143] Fix indentation. --- src/native/clr/host/host.cc | 4 ++-- src/native/clr/host/internal-pinvokes.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 02e26cb5541..a2eedaa2d6d 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -260,8 +260,8 @@ void Host::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass runtimeCl Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); jclass lrefLoaderClass = env->GetObjectClass (loader); - init.Loader_loadClass = env->GetMethodID (lrefLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - env->DeleteLocalRef (lrefLoaderClass); + init.Loader_loadClass = env->GetMethodID (lrefLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + env->DeleteLocalRef (lrefLoaderClass); init.grefLoader = env->NewGlobalRef (loader); init.grefIGCUserPeer = HostUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true); diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index afa27f9706c..39562e12ec5 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -7,7 +7,7 @@ using namespace xamarin::android; int _monodroid_gref_get () noexcept { - return OSBridge::get_gc_gref_count (); + return OSBridge::get_gc_gref_count (); } void _monodroid_gref_log (const char *message) noexcept @@ -16,7 +16,7 @@ void _monodroid_gref_log (const char *message) noexcept int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept { - return OSBridge::_monodroid_gref_log_new (curHandle, curType, newHandle, newType, threadName, threadId, from, from_writable); + return OSBridge::_monodroid_gref_log_new (curHandle, curType, newHandle, newType, threadName, threadId, from, from_writable); } void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept