diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index f42d1822c74..e8d5317bbd0 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -125,6 +125,8 @@ 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}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|AnyCPU = Debug|AnyCPU @@ -347,6 +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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -406,6 +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} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6} diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 99969ba29f6..43b89066856 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -39,8 +39,10 @@ projects that use the Microsoft.Android framework in .NET 6+. <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Mono.Android.Runtime.dll" /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\Mono.Android.Export.dll" /> - <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so" /> - <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so" /> + <_AndroidRuntimePackAssets 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 0a63d3bfcf0..272ff354bd5 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -137,6 +137,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/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs index 103d07403fc..a893fc1a96d 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs @@ -175,6 +175,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 167c48515f1..178fffce84b 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-ThirdParty/llvm/verbose_abort.cpp b/src-ThirdParty/llvm/verbose_abort.cpp deleted file mode 100644 index 719134e2ae5..00000000000 --- a/src-ThirdParty/llvm/verbose_abort.cpp +++ /dev/null @@ -1,77 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include <__config> -#include <__verbose_abort> -#include -#include -#include - -#ifdef __BIONIC__ -# include -# if __ANDROID_API__ >= 21 -# include -extern "C" void android_set_abort_message(const char* msg); -# else -# include -# endif // __ANDROID_API__ >= 21 -#endif // __BIONIC__ - -#if defined(__APPLE__) && __has_include() -# include -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -_LIBCPP_WEAK void __libcpp_verbose_abort(char const* format, ...) { - // Write message to stderr. We do this before formatting into a - // buffer so that we still get some information out if that fails. - { - va_list list; - va_start(list, format); - std::vfprintf(stderr, format, list); - va_end(list); - } - - // Format the arguments into an allocated buffer for CrashReport & friends. - // We leak the buffer on purpose, since we're about to abort() anyway. - char* buffer; - (void)buffer; - va_list list; - va_start(list, format); - -#if defined(__APPLE__) && __has_include() - // Note that we should technically synchronize accesses here (by e.g. taking a lock), - // however concretely we're only setting a pointer, so the likelihood of a race here - // is low. - vasprintf(&buffer, format, list); - CRSetCrashLogMessage(buffer); -#elif defined(__BIONIC__) - vasprintf(&buffer, format, list); - -# if __ANDROID_API__ >= 21 - // Show error in tombstone. - android_set_abort_message(buffer); - - // Show error in logcat. - openlog("libc++", 0, 0); - syslog(LOG_CRIT, "%s", buffer); - closelog(); -# else - // The good error reporting wasn't available in Android until L. Since we're - // about to abort anyway, just call __assert2, which will log _somewhere_ - // (tombstone and/or logcat) in older releases. - __assert2(__FILE__, __LINE__, __func__, buffer); -# endif // __ANDROID_API__ >= 21 -#endif - va_end(list); - - std::abort(); -} - -_LIBCPP_END_NAMESPACE_STD 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 10382ed3cc4..3b9038a84d5 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 @@ -232,6 +232,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" /> (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/Tasks/ProcessNativeLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs index 4970875d659..d0c1263bc29 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs @@ -59,11 +59,16 @@ public override bool RunTask () } continue; } - // Both libmono-android.debug.so and libmono-android.release.so are in InputLibraries. + // Both lib{mono,net}-android.debug.so and lib{mono,net}-android.release.so are in InputLibraries. // Use IncludeDebugSymbols to determine which one to include. - // We may eventually have files such as `libmono-android-checked+asan.release.so` as well. + // We may eventually have files such as `lib{mono,net}-android-checked+asan.release.so` as well. var fileName = Path.GetFileNameWithoutExtension (library.ItemSpec); - if (fileName.StartsWith ("libmono-android", StringComparison.Ordinal)) { + if (ExcludedLibraries != null && ExcludedLibraries.Contains (fileName, StringComparer.OrdinalIgnoreCase)) { + Log.LogDebugMessage ($"Excluding '{library.ItemSpec}'"); + continue; + } + + if (fileName.StartsWith ("libmono-android", StringComparison.Ordinal) || fileName.StartsWith ("libnet-android", StringComparison.Ordinal)) { if (fileName.EndsWith (".debug", StringComparison.Ordinal)) { if (!IncludeDebugSymbols) continue; @@ -73,6 +78,7 @@ public override bool RunTask () continue; library.SetMetadata ("ArchiveFileName", "libmonodroid.so"); } + Log.LogDebugMessage ($"Including runtime: {library}"); } else if (DebugNativeLibraries.Contains (fileName)) { if (!IncludeDebugSymbols) { Log.LogDebugMessage ($"Excluding '{library.ItemSpec}' for release builds."); @@ -82,9 +88,6 @@ public override bool RunTask () if (!wantedComponents.Contains (fileName)) { continue; } - } else if (ExcludedLibraries != null && ExcludedLibraries.Contains (fileName, StringComparer.OrdinalIgnoreCase)) { - Log.LogDebugMessage ($"Excluding '{library.ItemSpec}'"); - continue; } output.Add (library); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index 54d10a91441..69f5f2ca92d 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": 22488 + "Size": 22444 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 18208 + "Size": 18296 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 86368 + "Size": 86352 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 115752 + "Size": 116920 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { "Size": 22408 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24384 + "Size": 24376 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { "Size": 26480 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 633792 + "Size": 634384 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20048 + "Size": 20040 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21592 + "Size": 21584 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 20024 @@ -44,10 +44,10 @@ "Size": 87432 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 485800 + "Size": 1501240 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3196336 + "Size": 3196512 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 67248 @@ -62,7 +62,7 @@ "Size": 160232 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 17912 + "Size": 18264 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 2791957 + "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 43092050ff6..eb04b2212b1 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": 9172800 + "Size": 9172764 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -29,16 +29,16 @@ "Size": 2396 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 19456 + "Size": 19544 }, "lib/arm64-v8a/lib_FormsViewGroup.dll.so": { "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 94768 + "Size": 94736 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 523568 + "Size": 524256 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { "Size": 22408 @@ -47,10 +47,10 @@ "Size": 21432 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23080 + "Size": 23072 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 29808 + "Size": 29792 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { "Size": 36288 @@ -59,7 +59,7 @@ "Size": 25760 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23848 + "Size": 23840 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { "Size": 19584 @@ -71,31 +71,31 @@ "Size": 42456 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24424 + "Size": 24416 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19456 + "Size": 19448 }, "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { "Size": 28440 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 24696 + "Size": 24688 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19856 + "Size": 19848 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19432 + "Size": 19424 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30048 + "Size": 30040 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 49936 + "Size": 49928 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29488 + "Size": 29472 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { "Size": 33784 @@ -107,7 +107,7 @@ "Size": 38736 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 185816 + "Size": 185800 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { "Size": 89488 @@ -116,55 +116,55 @@ "Size": 41112 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21552 + "Size": 21544 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27072 + "Size": 27064 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 956368 + "Size": 956552 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 216688 + "Size": 216720 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { "Size": 62184 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 237096 + "Size": 237120 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 35592 + "Size": 35584 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { "Size": 20200 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21592 + "Size": 21584 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { - "Size": 54400 + "Size": 54408 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 19360 + "Size": 19352 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 20336 + "Size": 20328 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 21456 + "Size": 21448 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { "Size": 80496 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 183600 + "Size": 183584 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19256 + "Size": 19248 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19272 + "Size": 19264 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 22096 @@ -173,7 +173,7 @@ "Size": 34960 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.AppCompatResources.dll.so": { - "Size": 24520 + "Size": 24512 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.dll.so": { "Size": 163240 @@ -212,7 +212,7 @@ "Size": 31592 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.RecyclerView.dll.so": { - "Size": 112256 + "Size": 112248 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SavedState.dll.so": { "Size": 23144 @@ -221,7 +221,7 @@ "Size": 31952 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager.dll.so": { - "Size": 38056 + "Size": 38048 }, "lib/arm64-v8a/lib_Xamarin.Forms.Core.dll.so": { "Size": 581000 @@ -245,10 +245,10 @@ "Size": 87432 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 485800 + "Size": 1501240 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3196336 + "Size": 3196512 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 67248 @@ -263,7 +263,7 @@ "Size": 160232 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 349352 + "Size": 349440 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -416,7 +416,7 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { "Size": 98577 @@ -2486,5 +2486,5 @@ "Size": 812848 } }, - "PackageSize": 10628363 + "PackageSize": 10947851 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs new file mode 100644 index 00000000000..0e5593bb363 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs @@ -0,0 +1,52 @@ +using System; + +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 +// +// Type mappings: +// +// C++ C# +// -----------|---------- +// bool | bool +// uint8_t | byte +// int8_t | sbyte +// uint16_t | ushort +// int16_t | short +// uint32_t | uint +// int32_t | int +// uint64_t | ulong +// int64_t | long +// char* | string +// +// Names should be the same as in the above struct, but it's not a requirement +// (they will be used only to generate comments in the native code) +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 package_naming_policy; + public uint environment_variable_count; + public uint system_property_count; + public uint number_of_assemblies_in_apk; + public uint bundled_assembly_name_width; + public uint number_of_dso_cache_entries; + public uint number_of_aot_cache_entries; + public uint number_of_shared_libraries; + + [NativeAssembler (NumberFormat = LLVMIR.LlvmIrVariableNumberFormat.Hexadecimal)] + public uint android_runtime_jnienv_class_token; + + [NativeAssembler (NumberFormat = LLVMIR.LlvmIrVariableNumberFormat.Hexadecimal)] + public uint jnienv_initialize_method_token; + + [NativeAssembler (NumberFormat = LLVMIR.LlvmIrVariableNumberFormat.Hexadecimal)] + public uint jnienv_registerjninatives_method_token; + public uint jni_remapping_replacement_type_count; + public uint jni_remapping_replacement_method_index_entry_count; + public string android_package_name = String.Empty; +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs new file mode 100644 index 00000000000..24ec67e9e73 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + +using Java.Interop.Tools.TypeNameMappings; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Android.Tasks.LLVMIR; + +namespace Xamarin.Android.Tasks; + +class ApplicationConfigNativeAssemblyGeneratorCLR : LlvmIrComposer +{ + sealed class DSOCacheEntryContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var dso_entry = EnsureType (data); + if (String.Compare ("hash", fieldName, StringComparison.Ordinal) == 0) { + return $" from name: {dso_entry.HashedName}"; + } + + if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { + return $" name: {dso_entry.name}"; + } + + return String.Empty; + } + } + + // 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 + [NativeAssemblerStructContextDataProvider (typeof (DSOCacheEntryContextDataProvider))] + sealed class DSOCacheEntry + { + [NativeAssembler (Ignore = true)] + public string HashedName; + + [NativeAssembler (UsesDataProvider = true, NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public ulong hash; + + [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public ulong real_name_hash; + public bool ignore; + + [NativeAssembler (UsesDataProvider = true)] + public string name; + public IntPtr handle = IntPtr.Zero; + } + + sealed class DSOApkEntry + { + public ulong name_hash; + public uint offset; // offset into the APK + public int fd; // apk file descriptor + }; + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh AssemblyStoreAssemblyDescriptor structure + sealed class AssemblyStoreAssemblyDescriptor + { + public uint data_offset; + public uint data_size; + + public uint debug_data_offset; + public uint debug_data_size; + + public uint config_data_offset; + public uint config_data_size; + } + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh AssemblyStoreSingleAssemblyRuntimeData structure + sealed class AssemblyStoreSingleAssemblyRuntimeData + { + [NativePointer] + public byte image_data; + + [NativePointer] + public byte debug_info_data; + + [NativePointer] + public byte config_data; + + [NativePointer] + public AssemblyStoreAssemblyDescriptor descriptor; + } + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh AssemblyStoreRuntimeData structure + sealed class AssemblyStoreRuntimeData + { + [NativePointer (IsNull = true)] + public byte data_start; + public uint assembly_count; + public uint index_entry_count; + + [NativePointer (IsNull = true)] + public AssemblyStoreAssemblyDescriptor assemblies; + } + + sealed class XamarinAndroidBundledAssemblyContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override ulong GetBufferSize (object data, string fieldName) + { + var xaba = EnsureType (data); + if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { + return xaba.name_length; + } + + if (String.Compare ("file_name", fieldName, StringComparison.Ordinal) == 0) { + return xaba.name_length + MonoAndroidHelper.GetMangledAssemblyNameSizeOverhead (); + } + + return 0; + } + } + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh XamarinAndroidBundledAssembly structure + [NativeAssemblerStructContextDataProvider (typeof (XamarinAndroidBundledAssemblyContextDataProvider))] + sealed class XamarinAndroidBundledAssembly + { + public int file_fd; + + [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToPreAllocatedBuffer = true)] + public string file_name; + public uint data_offset; + public uint data_size; + + [NativePointer] + public byte data; + public uint name_length; + + [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToPreAllocatedBuffer = true)] + public string name; + } + + // 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; + StructureInstance? application_config; + List>? dsoCache; + List>? aotDsoCache; + List>? xamarinAndroidBundledAssemblies; + + StructureInfo? applicationConfigStructureInfo; + StructureInfo? dsoCacheEntryStructureInfo; + StructureInfo? dsoApkEntryStructureInfo; + StructureInfo? xamarinAndroidBundledAssemblyStructureInfo; + StructureInfo? assemblyStoreSingleAssemblyRuntimeDataStructureinfo; + StructureInfo? assemblyStoreRuntimeDataStructureInfo; + + 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; } + public int JNIEnvInitializeToken { get; set; } + public int JNIEnvRegisterJniNativesToken { get; set; } + public int JniRemappingReplacementTypeCount { get; set; } + public int JniRemappingReplacementMethodIndexEntryCount { get; set; } + public PackageNamingPolicy PackageNamingPolicy { get; set; } + public List NativeLibraries { get; set; } + public bool MarshalMethodsEnabled { get; set; } + public bool IgnoreSplitConfigs { get; set; } + + public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary environmentVariables, IDictionary systemProperties, TaskLoggingHelper log) + : base (log) + { + if (environmentVariables != null) { + this.environmentVariables = new SortedDictionary (environmentVariables, StringComparer.Ordinal); + } + + if (systemProperties != null) { + this.systemProperties = new SortedDictionary (systemProperties, StringComparer.Ordinal); + } + } + + protected override void Construct (LlvmIrModule module) + { + MapStructures (module); + + module.AddGlobalVariable ("format_tag", FORMAT_TAG, comment: $" 0x{FORMAT_TAG:x}"); + + var envVars = new LlvmIrGlobalVariable (environmentVariables, "app_environment_variables") { + Comment = " Application environment variables array, name:value", + }; + module.Add (envVars, stringGroupName: "env", stringGroupComment: " Application environment variables name:value pairs"); + + var sysProps = new LlvmIrGlobalVariable (systemProperties, "app_system_properties") { + Comment = " System properties defined by the application", + }; + module.Add (sysProps, stringGroupName: "sysprop", stringGroupComment: " System properties name:value pairs"); + + (dsoCache, aotDsoCache) = InitDSOCache (); + 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, + 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), + number_of_assemblies_in_apk = (uint)NumberOfAssembliesInApk, + number_of_shared_libraries = (uint)NativeLibraries.Count, + bundled_assembly_name_width = (uint)BundledAssemblyNameWidth, + number_of_dso_cache_entries = (uint)dsoCache.Count, + number_of_aot_cache_entries = (uint)aotDsoCache.Count, + android_runtime_jnienv_class_token = (uint)AndroidRuntimeJNIEnvToken, + jnienv_initialize_method_token = (uint)JNIEnvInitializeToken, + jnienv_registerjninatives_method_token = (uint)JNIEnvRegisterJniNativesToken, + jni_remapping_replacement_type_count = (uint)JniRemappingReplacementTypeCount, + jni_remapping_replacement_method_index_entry_count = (uint)JniRemappingReplacementMethodIndexEntryCount, + android_package_name = AndroidPackageName, + }; + application_config = new StructureInstance (applicationConfigStructureInfo, app_cfg); + module.AddGlobalVariable ("application_config", application_config); + + var dso_cache = new LlvmIrGlobalVariable (dsoCache, "dso_cache", LlvmIrVariableOptions.GlobalWritable) { + Comment = " DSO cache entries", + BeforeWriteCallback = HashAndSortDSOCache, + }; + module.Add (dso_cache); + + var aot_dso_cache = new LlvmIrGlobalVariable (aotDsoCache, "aot_dso_cache", LlvmIrVariableOptions.GlobalWritable) { + Comment = " AOT DSO cache entries", + BeforeWriteCallback = HashAndSortDSOCache, + }; + module.Add (aot_dso_cache); + + var dso_apk_entries = new LlvmIrGlobalVariable (typeof(List>), "dso_apk_entries") { + ArrayItemCount = (ulong)NativeLibraries.Count, + Options = LlvmIrVariableOptions.GlobalWritable, + ZeroInitializeArray = true, + }; + module.Add (dso_apk_entries); + + string bundledBuffersSize = xamarinAndroidBundledAssemblies == null ? "empty (unused when assembly stores are enabled)" : $"{BundledAssemblyNameWidth} bytes long"; + var bundled_assemblies = new LlvmIrGlobalVariable (typeof(List>), "bundled_assemblies", LlvmIrVariableOptions.GlobalWritable) { + Value = xamarinAndroidBundledAssemblies, + Comment = $" Bundled assembly name buffers, all {bundledBuffersSize}", + }; + module.Add (bundled_assemblies); + + AddAssemblyStores (module); + } + + void AddAssemblyStores (LlvmIrModule module) + { + ulong itemCount = (ulong)(NumberOfAssembliesInApk); + var assembly_store_bundled_assemblies = new LlvmIrGlobalVariable (typeof(List>), "assembly_store_bundled_assemblies", LlvmIrVariableOptions.GlobalWritable) { + ZeroInitializeArray = true, + ArrayItemCount = itemCount, + }; + module.Add (assembly_store_bundled_assemblies); + + var storeRuntimeData = new AssemblyStoreRuntimeData { + data_start = 0, + assembly_count = 0, + }; + + var assembly_store = new LlvmIrGlobalVariable ( + new StructureInstance(assemblyStoreRuntimeDataStructureInfo, storeRuntimeData), + "assembly_store", + LlvmIrVariableOptions.GlobalWritable + ); + module.Add (assembly_store); + } + + void HashAndSortDSOCache (LlvmIrVariable variable, LlvmIrModuleTarget target, object? state) + { + var cache = variable.Value as List>; + if (cache == null) { + throw new InvalidOperationException ($"Internal error: DSO cache must not be empty"); + } + + bool is64Bit = target.Is64Bit; + foreach (StructureInstance instance in cache) { + if (instance.Obj == null) { + throw new InvalidOperationException ("Internal error: DSO cache must not contain null entries"); + } + + var entry = instance.Obj as DSOCacheEntry; + if (entry == null) { + throw new InvalidOperationException ($"Internal error: DSO cache entry has unexpected type {instance.Obj.GetType ()}"); + } + + entry.hash = MonoAndroidHelper.GetXxHash (entry.HashedName, is64Bit); + entry.real_name_hash = MonoAndroidHelper.GetXxHash (entry.name, is64Bit); + } + + cache.Sort ((StructureInstance a, StructureInstance b) => a.Instance.hash.CompareTo (b.Instance.hash)); + } + + (List> dsoCache, List> aotDsoCache) InitDSOCache () + { + var dsos = new List<(string name, string nameLabel, bool ignore)> (); + var nameCache = new HashSet (StringComparer.OrdinalIgnoreCase); + + foreach (ITaskItem item in NativeLibraries) { + string? name = item.GetMetadata ("ArchiveFileName"); + if (String.IsNullOrEmpty (name)) { + name = item.ItemSpec; + } + name = Path.GetFileName (name); + + if (nameCache.Contains (name)) { + continue; + } + + dsos.Add ((name, $"dsoName{dsos.Count.ToString (CultureInfo.InvariantCulture)}", ELFHelper.IsEmptyAOTLibrary (Log, item.ItemSpec))); + } + + var dsoCache = new List> (); + var aotDsoCache = new List> (); + var nameMutations = new List (); + + for (int i = 0; i < dsos.Count; i++) { + string name = dsos[i].name; + nameMutations.Clear(); + AddNameMutations (name); + // All mutations point to the actual library name, but have hash of the mutated one + foreach (string entryName in nameMutations) { + var entry = new DSOCacheEntry { + HashedName = entryName, + hash = 0, // Hash is arch-specific, we compute it before writing + ignore = dsos[i].ignore, + name = name, + }; + + var item = new StructureInstance (dsoCacheEntryStructureInfo, entry); + if (name.StartsWith ("libaot-", StringComparison.OrdinalIgnoreCase)) { + aotDsoCache.Add (item); + } else { + dsoCache.Add (item); + } + } + } + + return (dsoCache, aotDsoCache); + + void AddNameMutations (string name) + { + nameMutations.Add (name); + if (name.EndsWith (".dll.so", StringComparison.OrdinalIgnoreCase)) { + string nameNoExt = Path.GetFileNameWithoutExtension (Path.GetFileNameWithoutExtension (name))!; + nameMutations.Add (nameNoExt); + + // This helps us at runtime, because sometimes MonoVM will ask for "AssemblyName" and sometimes for "AssemblyName.dll". + // In the former case, the runtime would ask for the "libaot-AssemblyName.so" image, which doesn't exist - we have + // "libaot-AssemblyName.dll.so" instead and, thus, we are forced to check for and append the missing ".dll" extension when + // loading the assembly, unnecessarily wasting time. + nameMutations.Add ($"{nameNoExt}.so"); + } else { + nameMutations.Add (Path.GetFileNameWithoutExtension (name)!); + } + + const string aotPrefix = "libaot-"; + if (name.StartsWith (aotPrefix, StringComparison.OrdinalIgnoreCase)) { + AddNameMutations (name.Substring (aotPrefix.Length)); + } + + const string libPrefix = "lib"; + if (name.StartsWith (libPrefix, StringComparison.OrdinalIgnoreCase)) { + AddNameMutations (name.Substring (libPrefix.Length)); + } + } + } + + void MapStructures (LlvmIrModule module) + { + applicationConfigStructureInfo = module.MapStructure (); + module.MapStructure (); + assemblyStoreSingleAssemblyRuntimeDataStructureinfo = module.MapStructure (); + assemblyStoreRuntimeDataStructureInfo = module.MapStructure (); + xamarinAndroidBundledAssemblyStructureInfo = module.MapStructure (); + dsoCacheEntryStructureInfo = module.MapStructure (); + dsoApkEntryStructureInfo = 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 19a844eab71..4e33b2af86a 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1,4 +1,4 @@ - + + + <_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')" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_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..462a62e36dc --- /dev/null +++ b/src/native-clr/runtime-base/CMakeLists.txt @@ -0,0 +1,51 @@ +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 new file mode 100644 index 00000000000..7946cc30580 --- /dev/null +++ b/src/native-clr/runtime-base/android-system.cc @@ -0,0 +1,330 @@ +#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 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..6cce7591a6a --- /dev/null +++ b/src/native-clr/runtime-base/util.cc @@ -0,0 +1,82 @@ +#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 new file mode 100644 index 00000000000..c1a85951663 --- /dev/null +++ b/src/native-clr/shared/CMakeLists.txt @@ -0,0 +1,50 @@ +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 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..2f6951c6275 --- /dev/null +++ b/src/native-clr/startup/CMakeLists.txt @@ -0,0 +1,53 @@ +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 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..2a34ff4c13d --- /dev/null +++ b/src/native-clr/xamarin-app-stub/application_dso_stub.cc @@ -0,0 +1,298 @@ +#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/CMakeLists.txt b/src/native/CMakeLists.txt index 6abbe4f5a03..b6109634c19 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -120,13 +120,8 @@ else() set(USES_LIBSTDCPP True) endif() -if(ANALYZERS_ENABLED) - message(STATUS "Analyzers enabled") - set(SHARED_LIB_NAME xa::shared-no-abi) -else() - message(STATUS "NO analyzers enabled") - set(SHARED_LIB_NAME xa::shared) -endif() +set(SHARED_LIB_NAME xa::shared) + # # Needed modules # diff --git a/src/native/CMakePresets.json.in b/src/native/CMakePresets.json.in index e7b90193064..33c910f6845 100644 --- a/src/native/CMakePresets.json.in +++ b/src/native/CMakePresets.json.in @@ -48,8 +48,8 @@ "hidden": true, "inherits": "common", "cacheVariables": { - "ANDROID_STL": "none", - "ANDROID_CPP_FEATURES": "no-rtti no-exceptions" + "ANDROID_STL": "c++_static", + "ANDROID_CPP_FEATURES": "no-rtti exceptions" } }, 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/monodroid/CMakeLists.txt b/src/native/monodroid/CMakeLists.txt index 8a5ebc0ec12..c191a6103bb 100644 --- a/src/native/monodroid/CMakeLists.txt +++ b/src/native/monodroid/CMakeLists.txt @@ -243,6 +243,12 @@ endmacro () lib_target_options(${XAMARIN_MONO_ANDROID_LIB}) 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,--no-undefined-version +) + if(BUILD_STATIC_LIBRARY) lib_target_options(${XAMARIN_MONO_ANDROID_STATIC_LIB}) xa_add_compile_definitions(${XAMARIN_MONO_ANDROID_STATIC_LIB}) diff --git a/src/native/monodroid/debug.cc b/src/native/monodroid/debug.cc index db787268f41..8839ded308a 100644 --- a/src/native/monodroid/debug.cc +++ b/src/native/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 '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", - mname.get (), - libname.get ()); + "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", + optional_string (mname.get ()), + optional_string (libname.get ()) + ); } /* Profiler support cribbed from mono/metadata/profiler.c */ @@ -108,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 '%s'? %p", symbol, func); + log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", optional_string (symbol), reinterpret_cast(func)); if (func != nullptr) { func (desc); @@ -138,7 +139,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, "Connection options: '%s'", options); + log_info (LOG_DEFAULT, "Connection options: '{}'", optional_string (options)); args = Util::monodroid_strsplit (options, ",", 0); @@ -148,21 +149,21 @@ 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 %d", port); + log_error (LOG_DEFAULT, "Invalid debug port value {}", port); continue; } conn_port = static_cast(port); - log_info (LOG_DEFAULT, "XS port = %d", conn_port); + log_info (LOG_DEFAULT, "XS port = {}", conn_port); } else if (strstr (arg, "timeout=") == arg) { char *endp; arg += strlen ("timeout="); opts->timeout_time = strtoll (arg, &endp, 10); if ((endp == arg) || (*endp != '\0')) - log_error (LOG_DEFAULT, "Invalid --timeout argument."); + log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, "Unknown connection option: '%s'", arg); + log_info (LOG_DEFAULT, "Unknown connection option: '{}'", optional_string (arg)); } } } @@ -186,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, "Not connecting to IDE as the timeout value has been reached; current-time: %lli timeout: %lli", 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; } @@ -197,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, "Failed to create connection thread: %s", strerror (errno)); + log_error (LOG_DEFAULT, "Failed to create connection thread: {}", strerror (errno)); return DebuggerConnectionStatus::Error; } @@ -218,8 +219,8 @@ Debug::start_debugging_and_profiling () if (res == DebuggerConnectionStatus::Error) { Helpers::abort_application ( LOG_DEBUGGER, - Util::monodroid_strdup_printf ( - "Connection to debugger failed. Args: %s", + std::format ( + "Connection to debugger failed. Args: {}", connect_args ) ); @@ -257,24 +258,24 @@ Debug::process_connection (int fd) ssize_t rv = Util::recv_uninterrupted (fd, &cmd_len, sizeof(cmd_len)); if (rv == 0) { - log_info (LOG_DEFAULT, "EOF on socket.\n"); + log_info (LOG_DEFAULT, "EOF on socket."sv); return false; } if (rv <= 0) { - log_info (LOG_DEFAULT, "Error while receiving command from XS (%s)\n", 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, "Error while receiving command from XS (%s)\n", 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, "Received cmd: '%s'.", command); + log_info (LOG_DEFAULT, "Received cmd: '{}'.", optional_string (command)); if (process_cmd (fd, command)) return true; @@ -286,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, "Could not create socket for XS to connect to: %s", 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, "Could not set SO_REUSEADDR on the listening socket (%s)", strerror (errno)); + log_info_nocheck_fmt (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno)); // not a fatal failure } @@ -307,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, "Could not bind to address: %s", strerror (errno)); + log_info (LOG_DEFAULT, "Could not bind to address: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -319,7 +320,7 @@ Debug::handle_server_connection (void) rv = listen (listen_socket, 1); if (rv == -1) { - log_info (LOG_DEFAULT, "Could not listen for XS: %s", strerror (errno)); + log_info (LOG_DEFAULT, "Could not listen for XS: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -362,14 +363,14 @@ Debug::handle_server_connection (void) if ((rv = select (listen_socket + 1, &rset, nullptr, nullptr, &tv)) == 0) { // timeout hit, no connections available. - log_info (LOG_DEFAULT, "Listened2 for connections from XS for 2 seconds, nobody connected.\n"); + log_info (LOG_DEFAULT, "Listened2 for connections from XS for 2 seconds, nobody connected."sv); rv = 3; goto cleanup; } } while (rv == -1 && errno == EINTR); if (rv == -1) { - log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: %s", strerror (errno)); + log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: {}", strerror (errno)); rv = 2; goto cleanup; } @@ -377,23 +378,23 @@ 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: %s", 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, "Could not set TCP_NODELAY on socket (%s)", strerror (errno)); + log_info (LOG_DEFAULT, "Could not set TCP_NODELAY on socket ({})", strerror (errno)); // not a fatal failure } - log_info (LOG_DEFAULT, "Successfully received connection from XS on port %i, fd: %i\n", listen_port, fd); + log_info (LOG_DEFAULT, "Successfully received connection from XS on port {}, fd: {}", listen_port, fd); need_new_conn = process_connection (fd); } - log_info (LOG_DEFAULT, "Successfully talked to XS. Will continue startup now.\n"); + log_info (LOG_DEFAULT, "Successfully talked to XS. Will continue startup now."sv); rv = 0; @@ -440,13 +441,13 @@ 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 (%s)\n", strerror (errno)); + log_error (LOG_DEFAULT, "Got keepalive request from XS, but could not send response back ({})", strerror (errno)); return false; } constexpr std::string_view EXIT_PROCESS_CMD { "exit process" }; if (strcmp (cmd, EXIT_PROCESS_CMD.data ()) == 0) { - log_info (LOG_DEFAULT, "Debugger requested an exit, will exit immediately.\n"); + log_info (LOG_DEFAULT, "Debugger requested an exit, will exit immediately."sv); fflush (stdout); fflush (stderr); exit (0); @@ -486,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: '%s'", prof); + log_error (LOG_DEFAULT, "Unknown profiler: '{}'", optional_string (prof)); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -495,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: '%s'", cmd); + log_error (LOG_DEFAULT, "Unsupported command: '{}'", optional_string (cmd)); } return false; @@ -525,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: %s", 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" }; @@ -552,7 +553,7 @@ Debug::start_profiling () if (!profiler_description) return; - log_info (LOG_DEFAULT, "Loading profiler: '%s'", profiler_description); + log_info (LOG_DEFAULT, "Loading profiler: '{}'", profiler_description); monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), profiler_description, nullptr); } @@ -572,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, "soft breakpoints enabled due to kernel version match (%s)", name.release); + log_info (LOG_DEBUGGER, "soft breakpoints enabled due to kernel version match ({})", name.release); return 1; } } @@ -580,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, "soft breakpoints enabled by default (%s 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, "soft breakpoints disabled (%s property set to %s)", 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 (%s property set to %s)", 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/monodroid/embedded-assemblies-zip.cc b/src/native/monodroid/embedded-assemblies-zip.cc index d807c633a23..453ff56d437 100644 --- a/src/native/monodroid/embedded-assemblies-zip.cc +++ b/src/native/monodroid/embedded-assemblies-zip.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -21,14 +22,14 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector= application_config.number_of_assemblies_in_apk || state.bundled_assemblies_slow_path) [[unlikely]] { if (!state.bundled_assemblies_slow_path && bundled_assembly_index == application_config.number_of_assemblies_in_apk) { - log_warn (LOG_ASSEMBLY, "Number of assemblies stored at build time (%u) was incorrect, switching to slow bundling path.", application_config.number_of_assemblies_in_apk); + log_warn ( + LOG_ASSEMBLY, + "Number of assemblies stored at build time ({}) was incorrect, switching to slow bundling path.", + application_config.number_of_assemblies_in_apk + ); } if (extra_bundled_assemblies == nullptr) { @@ -132,9 +137,14 @@ EmbeddedAssemblies::store_individual_assembly_data (dynamic_local_string if (number_of_mapped_assembly_stores > number_of_assembly_store_files) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Too many assembly stores. Expected at most %u", + std::format ( + "Too many assembly stores. Expected at most {}", number_of_assembly_store_files ) ); @@ -189,7 +199,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string int fd; bool close_fd; if (!AndroidSystem::is_embedded_dso_mode_enabled ()) { - log_debug (LOG_ASSEMBLY, "Mapping assembly blob file from filesystem"); + log_debug (LOG_ASSEMBLY, "Mapping assembly blob file from filesystem"sv); close_fd = true; // state.file_fd refers to the directory where our files live @@ -209,15 +219,15 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string } 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: %zu", 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) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Assembly store '%s' is not a valid .NET for Android assembly store file", - entry_name.get () + std::format ( + "Assembly store '{}' is not a valid .NET for Android assembly store file", + optional_string (entry_name.get ()) ) ); } @@ -225,9 +235,9 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Assembly store '%s' uses format version 0x%x, instead of the expected 0x%x", - entry_name.get (), + std::format ( + "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", + optional_string (entry_name.get ()), header->version, ASSEMBLY_STORE_FORMAT_VERSION ) @@ -257,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 ('%s')", 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; @@ -291,7 +301,15 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& apk_entry->offset = state.data_offset; apk_entry->fd = state.file_fd; - log_debug (LOG_ASSEMBLY, "Found a shared library entry %s (index: %u; name: %s; hash: 0x%llx; apk offset: %u)", entry_name.get (), number_of_zip_dso_entries, name, apk_entry->name_hash, apk_entry->offset); + 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 + ); number_of_zip_dso_entries++; } } @@ -307,27 +325,27 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus if (!zip_read_cd_info (fd, cd_offset, cd_size, cd_entries)) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( + std::format ( "Failed to read the EOCD record from APK file %s", - apk_name + optional_string (apk_name) ) ); } #ifdef DEBUG - log_info (LOG_ASSEMBLY, "Central directory offset: %u", cd_offset); - log_info (LOG_ASSEMBLY, "Central directory size: %u", cd_size); - log_info (LOG_ASSEMBLY, "Central directory entries: %u", 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) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Failed to seek to central directory position in APK: %s. retval=%d errno=%d, File=%s", + std::format ( + "Failed to seek to central directory position in APK: {}. retval={} errno={}, File={}", std::strerror (errno), retval, errno, - apk_name + optional_string (apk_name) ) ); } @@ -353,12 +371,12 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus if (static_cast(nread) != cd_size) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Failed to read Central Directory from APK: %s. nread=%d errno=%d File=%s", + std::format ( + "Failed to read Central Directory from APK: {}. nread={} errno={} File={}", std::strerror (errno), nread, errno, - apk_name + optional_string (apk_name) ) ); } @@ -394,8 +412,10 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, - "Set bundled assembly entry data. file name: '%s'; entry name: '%s'; data size: %u", - entry.file_name, entry.name, entry.data_size + "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", + optional_string (entry.file_name), + optional_string (entry.name), + entry.data_size ); } @@ -417,14 +437,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: %s (ret: %d; errno: %d)", 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, "Failed to read EOCD from the APK: %s (nread: %d; errno: %d)", 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; } @@ -432,7 +452,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ std::array signature; if (!zip_read_field (eocd, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD signature"); + log_error (LOG_ASSEMBLY, "Failed to read EOCD signature"sv); return false; } @@ -444,7 +464,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: %s (ret: %d; errno: %d)", 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; } @@ -453,7 +473,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: %s (nread: %d; errno: %d)", 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; } @@ -470,7 +490,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ } if (!found) { - log_error (LOG_ASSEMBLY, "Unable to find EOCD in the APK (with comment)"); + log_error (LOG_ASSEMBLY, "Unable to find EOCD in the APK (with comment)"sv); return false; } @@ -485,7 +505,11 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no 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 %u. %s (result: %d; errno: %d)", state.local_header_offset, result, errno); + 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; } @@ -494,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 %u: %s (nread: %d; errno: %d)", 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, "Failed to read Local Header entry signature at offset %u", 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, "Invalid Local Header entry signature at offset %u", 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, "Failed to read Local Header 'file name length' field at offset %u", (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, "Failed to read Local Header 'extra field length' field at offset %u", (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; } @@ -539,17 +563,17 @@ EmbeddedAssemblies::zip_extract_cd_info (std::array const& buf 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"); + 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"); + 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"); + log_error (LOG_ASSEMBLY, "Failed to read EOCD 'central directory offset' field"sv); return false; } @@ -561,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 %u bytes of data", to_read); + log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); return false; } @@ -637,51 +661,51 @@ EmbeddedAssemblies::zip_read_entry_info (std::vector const& buf, dynami std::array signature; if (!zip_read_field (buf, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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"); + 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); @@ -689,7 +713,7 @@ EmbeddedAssemblies::zip_read_entry_info (std::vector const& buf, dynami 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"); + log_error (LOG_ASSEMBLY, "Failed to read Central Directory entry 'file name' field"sv); return false; } diff --git a/src/native/monodroid/embedded-assemblies.cc b/src/native/monodroid/embedded-assemblies.cc index db3704f160f..6adb6f27fe6 100644 --- a/src/native/monodroid/embedded-assemblies.cc +++ b/src/native/monodroid/embedded-assemblies.cc @@ -86,13 +86,13 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb auto header = reinterpret_cast(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"); + 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, - Util::monodroid_strdup_printf ( - "Invalid compressed assembly descriptor index %u", + std::format ( + "Invalid compressed assembly descriptor index {}", header->descriptor_index ) ); @@ -111,8 +111,8 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb if (cad.data == nullptr) [[unlikely]] { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Invalid compressed assembly descriptor at %u: no data", + std::format ( + "Invalid compressed assembly descriptor at {}: no data", header->descriptor_index ) ); @@ -122,28 +122,28 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb if (header->uncompressed_length > cad.uncompressed_file_size) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Compressed assembly '%s' is larger than when the application was built (expected at most %u, got %u). Assemblies don't grow just like that!", - name, + 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), cad.uncompressed_file_size, header->uncompressed_length ) ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '%s' 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; } - const char *data_start = reinterpret_cast(data + sizeof(CompressedAssemblyHeader)); + const char *data_start = pointer_add(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, - Util::monodroid_strdup_printf ( - "Decompression of assembly %s failed with code %d", - name, + std::format ( + "Decompression of assembly {} failed with code {}", + optional_string (name), ret ) ); @@ -152,9 +152,9 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb if (static_cast(ret) != cad.uncompressed_file_size) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Decompression of assembly %s yielded a different size (expected %lu, got %u)", - name, + std::format ( + "Decompression of assembly {} yielded a different size (expected {}, got {})", + optional_string (name), cad.uncompressed_file_size, static_cast(ret) ) @@ -190,7 +190,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc int fd; bool close_fd; if (!AndroidSystem::is_embedded_dso_mode_enabled ()) { - log_debug (LOG_ASSEMBLY, "Mapping a runtime file from filesystem"); + log_debug (LOG_ASSEMBLY, "Mapping a runtime file from filesystem"sv); close_fd = true; // file.file_fd refers to the directory where our files live @@ -228,7 +228,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, "Assembly %s 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; } @@ -243,8 +243,17 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc header[j] = isprint (p [j]) ? p [j] : '.'; header [header.size () - 1] = '\0'; - log_info_nocheck (LOG_ASSEMBLY, "file-offset: % 8x start: %08p end: %08p len: % 12i zip-entry: %s name: %s [%s]", - (int) file.data_offset, file.data, file.data + file.data_size, (int) file.data_size, file.name, file.name, header.data ()); + log_info_nocheck_fmt ( + 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 () + ); } } } @@ -278,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: '%s'", abi_name.get ()); + log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", optional_string (abi_name.get ())); } } @@ -312,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, "Debug info file '%s' 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)); } @@ -324,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, "Failed to load managed assembly '%s'. %s", 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; } @@ -339,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: '%s'", 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 @@ -386,19 +395,19 @@ force_inline MonoAssembly* 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: '%s' (hash 0x%zx)", 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, "Assembly '%s' (hash 0x%zx) not found", name.get (), name_hash); + log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.get ()), name_hash); return nullptr; } if (hash_entry->descriptor_index >= assembly_store.assembly_count) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Invalid assembly descriptor index %u, exceeds the maximum value of %u", + std::format ( + "Invalid assembly descriptor index {}, exceeds the maximum value of {}", hash_entry->descriptor_index, assembly_store.assembly_count - 1 ) @@ -419,15 +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 () + optional_string (name.get ()) ); } @@ -437,7 +446,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string 0) { const Entry *ret; if constexpr (use_precalculated_size) { - ret = reinterpret_cast(reinterpret_cast(base) + (precalculated_size * (nmemb / 2))); + ret = pointer_add(reinterpret_cast(base), precalculated_size * (nmemb / 2)); } else { ret = base + (nmemb / 2); } @@ -558,7 +567,7 @@ EmbeddedAssemblies::binary_search (const Key *key, const Entry *base, size_t nme nmemb /= 2; } else if (result > 0) { if constexpr (use_precalculated_size) { - base = reinterpret_cast(reinterpret_cast(ret) + precalculated_size); + base = pointer_add(reinterpret_cast(ret), precalculated_size); } else { base = ret + 1; } @@ -611,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, "typemap: unable to find mapping to a managed type from Java type '%s'", 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, "typemap: Java type '%s' 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, "typemap: Java type '%s' corresponds to managed type '%s'", java_type_name.get (), managed_type_name); + log_debug (LOG_DEFAULT, "typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), optional_string (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 '%s' (mapped from Java type '%s') 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 '%s'", managed_type_name); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '{}'", optional_string (managed_type_name)); return nullptr; } @@ -650,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, "typemap: unable to find mapping to a managed type from Java type '%s' (hash 0x%zx)", 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, "typemap: mapping from Java type '%s' to managed type has invalid module index %u", 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, "typemap: unable to find mapping from Java type '%s' to managed type with token ID %u in module [%s]", 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; } @@ -667,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 '%s' 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, "typemap: failed to create Mono assembly name for '%s'", 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 (); @@ -683,22 +692,28 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (assm == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: failed to load managed assembly '%s'", 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 '%s' when looking up managed type corresponding to Java type '%s'", 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; } } - log_debug (LOG_ASSEMBLY, "typemap: java type '%s' corresponds to managed token id %u (0x%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, "typemap: unable to find managed type with token ID %u in assembly '%s', corresponding to Java type '%s'", 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; } @@ -709,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 %u in assembly '%s', corresponding to Java type '%s'", 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; } @@ -727,7 +747,7 @@ EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type) noexcept } if (java_type == nullptr) [[unlikely]]{ - log_warn (LOG_ASSEMBLY, "typemap: null 'java_type' passed to 'typemap_java_to_managed'"); + log_warn (LOG_ASSEMBLY, "typemap: null 'java_type' passed to 'typemap_java_to_managed'"sv); return nullptr; } @@ -735,7 +755,7 @@ EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type) noexcept // number of bytes. int name_len = mono_string_length (java_type) << 1; if (name_len <= 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: empty 'java_type' passed to 'typemap_java_to_managed'"); + log_warn (LOG_ASSEMBLY, "typemap: empty 'java_type' passed to 'typemap_java_to_managed'"sv); return nullptr; } @@ -774,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 '%s'", 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; } @@ -793,57 +813,74 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapModule *match = mvid != nullptr ? binary_search (mvid, map_modules, map_module_count) : nullptr; if (match == nullptr) { if (mvid == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"); + 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 [%s] 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, "typemap: MVID [%s] maps to assembly %s, looking for token %d (0x%x), table index %d", 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) { if (match->map == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: module with mvid [%s] 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; } if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: searching module [%s] duplicate map for token %u (0x%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, "typemap: type with token %d (0x%x) in module {%s} (%s) 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, "typemap: type with token %d (0x%x) in module {%s} (%s) has invalid Java type index %u", 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 %d (0x%x) in module {%s} (%s) points to invalid Java type at index %u (invalid type name index %u)", 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]; if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index %u", 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, - "typemap: type with token %d (0x%x) in module {%s} (%s) corresponds to Java type '%s'", + "typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", token, token, MonoGuidString (mvid).get (), - match->assembly_name, + optional_string (match->assembly_name), ret ); @@ -862,7 +899,7 @@ EmbeddedAssemblies::typemap_managed_to_java (MonoReflectionType *reflection_type MonoType *type = mono_reflection_type_get_type (reflection_type); if (type == nullptr) { - log_warn (LOG_ASSEMBLY, "Failed to map reflection type to MonoType"); + log_warn (LOG_ASSEMBLY, "Failed to map reflection type to MonoType"sv); return nullptr; } @@ -891,22 +928,31 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons if (mmap_info.area == MAP_FAILED) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Could not mmap APK fd %d: %s; File=%s", + std::format ( + "Could not mmap APK fd {}: {}; File={}", fd, strerror (errno), - filename + optional_string (filename) ) ); } mmap_info.size = offsetSize; - file_info.area = (void*)((const char*)mmap_info.area + offsetFromPage); + file_info.area = pointer_add (mmap_info.area, offsetFromPage); file_info.size = size; - log_info (LOG_ASSEMBLY, " mmap_start: %08p mmap_end: %08p mmap_len: % 12u file_start: %08p file_end: %08p file_len: % 12u apk descriptor: %d file: %s", - mmap_info.area, reinterpret_cast (mmap_info.area) + mmap_info.size, mmap_info.size, - file_info.area, reinterpret_cast (file_info.area) + file_info.size, file_info.size, fd, filename); + 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, + optional_string (filename) + ); return file_info; } @@ -919,13 +965,13 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro if ((fd = open (apk, O_RDONLY)) < 0) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "ERROR: Unable to load application package %s.", - apk + std::format ( + "ERROR: Unable to load application package {}.", + optional_string (apk) ) ); } - log_debug (LOG_ASSEMBLY, "APK %s FD: %d", apk, fd); + log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk), fd); zip_load_entries (fd, apk, should_register); } @@ -952,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 %s file '%s/%s': %s", 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: %s file '%s/%s' is too small (must be at least %u 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 %s file %s/%s for reading: %s", 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 %s file header from '%s/%s': %s", 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 %s file header from '%s/%s'", 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 %s file header from '%s/%s': expected 0x%X, got 0x%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 %s format version. This build supports only version %u, file '%s/%s' uses version %u", 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; } @@ -998,14 +1094,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 %u, found %u 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, "typemap: failed to read %u bytes from index file. %s", data_size, strerror (errno)); + log_error (LOG_ASSEMBLY, "typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno)); return nullptr; } @@ -1021,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 '%s/%s'", 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; @@ -1048,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, "tyemap: failed to read map assembly name from '%s/%s': %s", 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; } @@ -1057,8 +1159,14 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, - "typemap: '%s/%s':: entry count == %u; Java name field width == %u; Managed name width == %u; assembly name length == %u; assembly name == %s", - 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 == {}", + 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) ); // [name][index] @@ -1072,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, "tyemap: failed to read map data from '%s/%s': %s", 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; } @@ -1095,7 +1203,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * // integer from unaligned memory memcpy (&idx, java_pos + header.java_name_width, sizeof (idx)); if (idx < INVALID_TYPE_INDEX) { - cur->to = reinterpret_cast(managed_start + (managed_entry_size * idx)); + cur->to = pointer_add(managed_start, managed_entry_size * idx); } else { // Ignore the type mapping cur->to = nullptr; @@ -1106,7 +1214,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * cur->from = reinterpret_cast(managed_pos); memcpy (&idx, managed_pos + header.managed_name_width, sizeof (idx)); - cur->to = reinterpret_cast(java_start + (java_entry_size * idx)); + cur->to = pointer_add(java_start, java_entry_size * idx); managed_pos += managed_entry_size; } @@ -1116,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 '%s/%s'", 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; @@ -1155,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 '%s' contains %i 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; } @@ -1259,10 +1367,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( force_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 '%s'", 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 '%s': %s", 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; } @@ -1271,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 '%s': %s", 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 %d for directory '%s': %s", 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; } @@ -1295,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 '%s': %s", 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 @@ -1315,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 '%s'", 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; @@ -1344,7 +1452,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look size_t EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, "Registering assemblies from the filesystem"); + log_debug (LOG_ASSEMBLY, "Registering assemblies from the filesystem"sv); constexpr bool LookForMangledNames = true; size_t assembly_count = register_from_filesystem ( AndroidSystem::app_lib_directories[0], @@ -1362,6 +1470,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, "Found %zu 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/monodroid/embedded-assemblies.hh b/src/native/monodroid/embedded-assemblies.hh index ff153942724..341ecc2a086 100644 --- a/src/native/monodroid/embedded-assemblies.hh +++ b/src/native/monodroid/embedded-assemblies.hh @@ -20,6 +20,7 @@ #include #include "archive-dso-stub-config.hh" +#include "log_types.hh" #include "strings.hh" #include "xamarin-app.hh" #include "cpp-util.hh" @@ -309,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: %s", 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 }; } @@ -328,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 %zu", 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; @@ -356,6 +357,11 @@ namespace xamarin::android::internal { force_inline static c_unique_ptr to_utf8 (const MonoString *s) noexcept { + if (s == nullptr) [[unlikely]] { + // We need to duplicate mono_string_to_utf8 behavior + return c_unique_ptr (strdup ("")); + } + return c_unique_ptr (mono_string_to_utf8 (const_cast(s))); } @@ -430,7 +436,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, "Unmangled name to '%s'", name.get ()); + log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", optional_string (name.get ())); }; private: diff --git a/src/native/monodroid/internal-pinvokes.cc b/src/native/monodroid/internal-pinvokes.cc index 81367aaea29..cd89f4c619b 100644 --- a/src/native/monodroid/internal-pinvokes.cc +++ b/src/native/monodroid/internal-pinvokes.cc @@ -1,3 +1,5 @@ +#include + #include "android-system.hh" #include "globals.hh" #include "internal-pinvokes.hh" @@ -31,30 +33,30 @@ monodroid_log (LogLevel level, LogCategories category, const char *message) switch (level) { case LogLevel::Verbose: case LogLevel::Debug: - log_debug_nocheck (category, message); + log_debug_nocheck (category, std::string_view { message }); break; case LogLevel::Info: - log_info_nocheck (category, message); + log_info_nocheck (category, std::string_view { message }); break; case LogLevel::Warn: case LogLevel::Silent: // warn is always printed - log_warn (category, message); + log_warn (category, std::string_view { message }); break; case LogLevel::Error: - log_error (category, message); + log_error (category, std::string_view { message }); break; case LogLevel::Fatal: - log_fatal (category, message); + log_fatal (category, std::string_view { message }); break; default: case LogLevel::Unknown: case LogLevel::Default: - log_info_nocheck (category, message); + log_info_nocheck (category, std::string_view { message }); break; } } @@ -156,7 +158,7 @@ _monodroid_timezone_get_default_id () const char *mutf8 = env->GetStringUTFChars (id, nullptr); if (mutf8 == nullptr) { - log_error (LOG_DEFAULT, "Failed to convert Java TimeZone ID to UTF8 (out of memory?)"); + log_error (LOG_DEFAULT, "Failed to convert Java TimeZone ID to UTF8 (out of memory?)"sv); env->DeleteLocalRef (id); env->DeleteLocalRef (d); return nullptr; diff --git a/src/native/monodroid/mono-image-loader.hh b/src/native/monodroid/mono-image-loader.hh index 783b6af679c..48812d223b2 100644 --- a/src/native/monodroid/mono-image-loader.hh +++ b/src/native/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, "Failed to open assembly image. %s", mono_image_strerror (status)); + log_warn (LOG_ASSEMBLY, "Failed to open assembly image. {}", optional_string (mono_image_strerror (status))); return nullptr; } @@ -119,8 +119,8 @@ namespace xamarin::android::internal { if (index < 0) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Failed to look up image index for hash 0x%zx", + std::format ( + "Failed to look up image index for hash {:x}", hash ) ); diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh index 59f00ceffd2..da7f9f6be2c 100644 --- a/src/native/monodroid/monodroid-glue-internal.hh +++ b/src/native/monodroid/monodroid-glue-internal.hh @@ -166,7 +166,7 @@ namespace xamarin::android::internal void *symptr = MonodroidDl::monodroid_dlsym (handle, name, &err, nullptr); if (symptr == nullptr) { - log_warn (LOG_DEFAULT, "Failed to load symbol '%s' library with handle %p. %s", name, handle, err == nullptr ? "Unknown error" : err); + 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/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc index a90e239e83f..7a28622554f 100644 --- a/src/native/monodroid/monodroid-glue.cc +++ b/src/native/monodroid/monodroid-glue.cc @@ -95,7 +95,7 @@ MonodroidRuntime::thread_end ([[maybe_unused]] MonoProfiler *prof, [[maybe_unuse if (r != JNI_OK) { #if DEBUG /* - log_fatal (LOG_DEFAULT, "ERROR: Unable to detach current thread from the Java VM!"); + log_fatal (LOG_DEFAULT, "ERROR: Unable to detach current thread from the Java VM!"sv); */ #endif } @@ -174,15 +174,15 @@ 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: %s\n", 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 '%s'. %s", 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"); + log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); } if (result != nullptr) { // TODO: register .mdb, .pdb file @@ -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, "open_from_update_dir: loaded assembly: %p\n", 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, "Found stale %s property with value '%s', 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; } } @@ -392,7 +392,7 @@ bool MonodroidRuntime::parse_runtime_args (dynamic_local_string &runtime_args, RuntimeOptions *options) noexcept { if (runtime_args.length () == 0) { - log_warn (LOG_DEFAULT, "runtime args empty"); + log_warn (LOG_DEFAULT, "runtime args empty"sv); return true; } @@ -422,7 +422,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid SDB port value %d", 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, "Invalid output port value %d", out_port); + log_error (LOG_DEFAULT, "Invalid output port value {}", out_port); ret = false; continue; } @@ -468,19 +468,19 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_stringout_port = out_port == -1 ? 0 : static_cast(out_port); } else if (token.starts_with (ARG_TIMEOUT)) { if (!token.to_integer (options->timeout_time, ARG_TIMEOUT.length ())) { - log_error (LOG_DEFAULT, "Invalid --timeout argument."); + log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); ret = false; } } else if (token.starts_with (ARG_SERVER)) { options->server = token.has_at ('y', ARG_SERVER.length ()) || token.has_at ('Y', ARG_SERVER.length ()); } else if (token.starts_with (ARG_LOGLEVEL)) { if (!token.to_integer (options->loglevel, ARG_LOGLEVEL.length ())) { - log_error (LOG_DEFAULT, "Invalid --loglevel argument."); + log_error (LOG_DEFAULT, "Invalid --loglevel argument."sv); ret = false; } } else { static_local_string arg (token); - log_error (LOG_DEFAULT, "Unknown runtime argument: '%s'", arg.get ()); + log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", optional_string (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: '%s'", 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: %lli timeout: %lli", 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,15 +537,15 @@ 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: %s", 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); if (sock < 0) { Helpers::abort_application ( LOG_DEBUGGER, - Util::monodroid_strdup_printf ( - "Could not construct a socket for stdout and stderr; does your app have the android.permission.INTERNET permission? %s", + std::format ( + "Could not construct a socket for stdout and stderr; does your app have the android.permission.INTERNET permission? {}", strerror (errno) ) ); @@ -561,22 +561,22 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if ((r = inet_pton (AF_INET, options.host, &addr.sin_addr)) != 1) { Helpers::abort_application ( LOG_DEBUGGER, - Util::monodroid_strdup_printf ( - "Could not setup a socket for stdout and stderr: %s", - r == -1 ? strerror (errno) : "address not parseable in the specified address family" + std::format ( + "Could not setup a socket for stdout and stderr: {}", + r == -1 ? strerror (errno) : "address not parseable in the specified address family"sv ) ); } if (options.server) { int accepted = monodroid_debug_accept (sock, addr); - log_warn (LOG_DEBUGGER, "Accepted stdout connection: %d", accepted); + log_warn (LOG_DEBUGGER, "Accepted stdout connection: {}", accepted); if (accepted < 0) { Helpers::abort_application ( LOG_DEBUGGER, - Util::monodroid_strdup_printf ( - "Error accepting stdout and stderr (%s:%d): %s", - options.host, + std::format ( + "Error accepting stdout and stderr ({}:{}): {}", + optional_string (options.host), options.out_port, strerror (errno) ) @@ -589,9 +589,9 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (monodroid_debug_connect (sock, addr) != 1) { Helpers::abort_application ( LOG_DEBUGGER, - Util::monodroid_strdup_printf ( - "Error connecting stdout and stderr (%s:%d): %s", - options.host, + std::format ( + "Error connecting stdout and stderr ({}:{}): {}", + optional_string (options.host), options.out_port, strerror (errno) ) @@ -651,7 +651,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse parse_gdb_options (); if (wait_for_gdb) { - log_warn (LOG_DEFAULT, "Waiting for gdb to attach..."); + log_warn (LOG_DEFAULT, "Waiting for gdb to attach..."sv); while (monodroid_gdb_wait) { sleep (1); } @@ -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 '%s' as extra arguments to the runtime.\n", 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; @@ -729,17 +729,19 @@ 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 '%s' or '%s'. 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] : ""); + 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]) : "" + ); #else - log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"); + log_fatal (LOG_DEFAULT, "No assemblies (or assembly blobs) were found in the application APK file(s) or on the filesystem"sv); #endif constexpr const char *assemblies_prefix = EmbeddedAssemblies::get_assemblies_prefix ().data (); Helpers::abort_application ( - Util::monodroid_strdup_printf ( - "ALL entries in APK named `%s` MUST be STORED. Gradle's minification may COMPRESS such entries.", - assemblies_prefix + std::format ( + "ALL entries in APK named `{}` MUST be STORED. Gradle's minification may COMPRESS such entries.", + optional_string (assemblies_prefix) ) ); } @@ -854,7 +856,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: %i", 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;"); @@ -931,7 +933,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec osBridge.initialize_on_runtime_init (env, runtimeClass); - log_debug (LOG_DEFAULT, "Calling into managed runtime init"); + log_debug (LOG_DEFAULT, "Calling into managed runtime init"sv); size_t native_to_managed_index; if (FastTiming::enabled ()) [[unlikely]] { @@ -940,7 +942,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: %s", 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 ( @@ -996,7 +998,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 %s. %s", 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); } @@ -1006,10 +1008,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: %s", 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 %s. %s", 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); } @@ -1038,7 +1040,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, "Env variable '%s' set to '%s'.", name, v); + log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", optional_string (name), optional_string (v)); }; string_segment arg_token; @@ -1058,7 +1060,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: '%s'", arg.get ()); + log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", optional_string (arg.get ())); } else { // ’name=value’ arg[index] = '\0'; @@ -1138,10 +1140,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 '%s'. %s", 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: %s", 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 ()); } @@ -1155,7 +1157,7 @@ MonodroidRuntime::load_assembly (MonoAssemblyLoadContextGCHandle alc_handle, jst const char *assm_name = assembly.get_cstr (); if (assm_name == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to load assembly into ALC, name is null"); + log_warn (LOG_ASSEMBLY, "Unable to load assembly into ALC, name is null"sv); return; } @@ -1187,7 +1189,7 @@ MonodroidRuntime::load_assembly (MonoDomain *domain, jstring_wrapper &assembly) const char *assm_name = assembly.get_cstr (); if (assm_name == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to load assembly into AppDomain, name is null"); + log_warn (LOG_ASSEMBLY, "Unable to load assembly into AppDomain, name is null"sv); return; } @@ -1268,7 +1270,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)); @@ -1466,7 +1468,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: %s", AndroidSystem::get_runtime_libdir ()); + log_debug (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); } AndroidSystem::setup_process_args (runtimeApks); @@ -1480,25 +1482,25 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl debug.start_debugging_and_profiling (); #endif - log_debug (LOG_DEFAULT, "Probing for Mono AOT mode\n"); + log_debug (LOG_DEFAULT, "Probing for Mono AOT mode"sv); MonoAotMode mode = MonoAotMode::MONO_AOT_MODE_NONE; if (AndroidSystem::is_mono_aot_enabled ()) { mode = AndroidSystem::get_mono_aot_mode (); if (mode != MonoAotMode::MONO_AOT_MODE_INTERP_ONLY) { - log_debug (LOG_DEFAULT, "Enabling AOT mode in Mono"); + log_debug (LOG_DEFAULT, "Enabling AOT mode in Mono"sv); } else { - log_debug (LOG_DEFAULT, "Enabling Mono Interpreter"); + log_debug (LOG_DEFAULT, "Enabling Mono Interpreter"sv); } } mono_jit_set_aot_mode (mode); - log_debug (LOG_DEFAULT, "Probing if we should use LLVM\n"); + log_debug (LOG_DEFAULT, "Probing if we should use LLVM"sv); if (AndroidSystem::is_mono_llvm_enabled ()) { char *args [1]; args[0] = const_cast ("--llvm"); - log_debug (LOG_DEFAULT, "Enabling LLVM mode in Mono\n"); + log_debug (LOG_DEFAULT, "Enabling LLVM mode in Mono"sv); mono_jit_parse_options (1, args); mono_set_use_llvm (true); } @@ -1529,9 +1531,9 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl } if (Util::should_log (LOG_DEFAULT)) [[unlikely]] { - log_info_nocheck ( + log_info_nocheck_fmt ( LOG_DEFAULT, - ".NET for Android version: %s (%s; %s); built on %s; NDK version: %s; API level: %s; MonoVM version: %s", + ".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", BuildInfo::xa_version.data (), BuildInfo::architecture.data (), BuildInfo::kind.data (), @@ -1661,13 +1663,13 @@ 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", klass); + 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?)"); + log_error (LOG_DEFAULT, "Failed to convert Java class name to UTF8 (out of memory?)"sv); env->DeleteLocalRef (name); return nullptr; } diff --git a/src/native/monodroid/monodroid-networkinfo.cc b/src/native/monodroid/monodroid-networkinfo.cc index 50267299def..4e87c0079d3 100644 --- a/src/native/monodroid/monodroid-networkinfo.cc +++ b/src/native/monodroid/monodroid-networkinfo.cc @@ -76,10 +76,10 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo if (!NetworkInterface_class || !NetworkInterface_getByName) { if (!NetworkInterface_class) - log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface' Java class"); + log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface' Java class"sv); if (!NetworkInterface_getByName) - log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface.getByName' function"); - log_warn (LOG_NET, "Unable to determine network interface state because of missing Java API"); + log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface.getByName' function"sv); + log_warn (LOG_NET, "Unable to determine network interface state because of missing Java API"sv); goto leave; } @@ -88,21 +88,21 @@ _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, "Java exception occurred while looking up the interface '%s'", 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, "Failed to look up interface '%s' using Java API", ifname); + log_warn (LOG_NET, "Failed to look up interface '{}' using Java API", ifname); ret = FALSE; goto leave; } if (is_up) { if (!NetworkInterface_isUp) { - log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface.isUp' function. Unable to determine interface operational state"); + log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface.isUp' function. Unable to determine interface operational state"sv); ret = FALSE; } else *is_up = (mono_bool)env->CallBooleanMethod (networkInterface, NetworkInterface_isUp); @@ -110,7 +110,7 @@ _monodroid_get_network_interface_state (const char *ifname, mono_bool *is_up, mo if (supports_multicast) { if (!NetworkInterface_supportsMulticast) { - log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface.supportsMulticast' function. Unable to determine whether interface supports multicast"); + log_warn (LOG_NET, "Failed to find the 'java.net.NetworkInterface.supportsMulticast' function. Unable to determine whether interface supports multicast"sv); ret = FALSE; } else *supports_multicast = (mono_bool)env->CallBooleanMethod (networkInterface, NetworkInterface_supportsMulticast); @@ -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 '%s' 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); @@ -143,7 +143,7 @@ int _monodroid_get_dns_servers (void **dns_servers_array) { if (!dns_servers_array) { - log_warn (LOG_NET, "Unable to get DNS servers, no location to store data in"); + log_warn (LOG_NET, "Unable to get DNS servers, no location to store data in"sv); return -1; } *dns_servers_array = nullptr; diff --git a/src/native/monodroid/monodroid-tracing.cc b/src/native/monodroid/monodroid-tracing.cc index 7b5c3d9e4f2..96c9778dd37 100644 --- a/src/native/monodroid/monodroid-tracing.cc +++ b/src/native/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 '%s'. %s", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error" : 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/monodroid/osbridge.cc b/src/native/monodroid/osbridge.cc index d2725d278e2..4d03b3600bb 100644 --- a/src/native/monodroid/osbridge.cc +++ b/src/native/monodroid/osbridge.cc @@ -188,10 +188,10 @@ 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, "%s", m); + log_debug (category, "{}", optional_string (m)); } if (to != nullptr) { - fprintf (to, "%s\n", m); + fprintf (to, "%s\n", optional_string (m)); fflush (to); } *end = c; @@ -202,11 +202,11 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, "%s", message); + log_debug (LOG_GREF, "{}", optional_string (message)); } if (!gref_log) return; - fprintf (gref_log, "%s", message); + fprintf (gref_log, "%s", optional_string (message)); fflush (gref_log); } @@ -216,20 +216,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 %i gwrefc %i obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%i)", - c, - gc_weak_gref_count, - curHandle, - curType, - newHandle, - newType, - threadName, - threadId); + + 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 (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "%s", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -241,7 +244,7 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH curType, newHandle, newType, - threadName, + optional_string (threadName), threadId); if (from_writable) _write_stack_trace (gref_log, const_cast(from)); @@ -259,18 +262,20 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr int c = _monodroid_gref_dec (); if ((log_categories & LOG_GREF) == 0) return; - log_info (LOG_GREF, "-g- grefc %i gwrefc %i handle %p/%c from thread '%s'(%i)", - c, - gc_weak_gref_count, - handle, - type, - threadName, - threadId); + 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 (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "%s", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -280,12 +285,12 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr gc_weak_gref_count, handle, type, - threadName, + optional_string (threadName), threadId); if (from_writable) _write_stack_trace (gref_log, const_cast(from)); else - fprintf (gref_log, "%s\n", from); + fprintf (gref_log, "%s\n", optional_string (from)); fflush (gref_log); } @@ -296,20 +301,22 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new ++gc_weak_gref_count; if ((log_categories & LOG_GREF) == 0) return; - log_info (LOG_GREF, "+w+ grefc %i gwrefc %i obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%i)", - gc_gref_count, - gc_weak_gref_count, - curHandle, - curType, - newHandle, - newType, - threadName, - threadId); + 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 + ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "%s", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -321,12 +328,12 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new curType, newHandle, newType, - threadName, + optional_string (threadName), threadId); if (from_writable) _write_stack_trace (gref_log, const_cast(from)); else - fprintf (gref_log, "%s\n", from); + fprintf (gref_log, "%s\n", optional_string (from)); fflush (gref_log); } @@ -337,18 +344,20 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th --gc_weak_gref_count; if ((log_categories & LOG_GREF) == 0) return; - log_info (LOG_GREF, "-w- grefc %i gwrefc %i handle %p/%c from thread '%s'(%i)", - gc_gref_count, - gc_weak_gref_count, - handle, - type, - threadName, - threadId); + 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 + ); if (gref_to_logcat) { if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "%s", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!gref_log) @@ -358,12 +367,12 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th gc_weak_gref_count, handle, type, - threadName, + optional_string (threadName), threadId); if (from_writable) _write_stack_trace (gref_log, const_cast(from)); else - fprintf (gref_log, "%s\n", from); + fprintf (gref_log, "%s\n", optional_string (from)); fflush (gref_log); } @@ -373,17 +382,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 %i handle %p/%c from thread '%s'(%i)", - lrefc, - handle, - type, - threadName, - threadId); + log_info (LOG_LREF, + "+l+ lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + 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, "%s", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!lref_log) @@ -392,12 +403,12 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c lrefc, handle, type, - threadName, + optional_string (threadName), threadId); if (from_writable) _write_stack_trace (lref_log, const_cast(from)); else - fprintf (lref_log, "%s\n", from); + fprintf (lref_log, "%s\n", optional_string (from)); fflush (lref_log); } @@ -407,17 +418,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 %i handle %p/%c from thread '%s'(%i)", - lrefc, - handle, - type, - threadName, - threadId); + log_info (LOG_LREF, + "-l- lrefc {} handle {:p}/{} from thread '{}'({})", + lrefc, + reinterpret_cast(handle), + type, + 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, "%s", from); + log_info (LOG_GREF, "{}", optional_string (from)); } } if (!lref_log) @@ -426,12 +439,12 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons lrefc, handle, type, - threadName, + optional_string (threadName), threadId); if (from_writable) _write_stack_trace (lref_log, const_cast(from)); else - fprintf (lref_log, "%s\n", from); + fprintf (lref_log, "%s\n", optional_string (from)); fflush (lref_log); } @@ -529,9 +542,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 %s.%s is a bridge before we inited java.lang.Object", - mono_class_get_namespace (klass), - mono_class_get_name (klass)); + 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)) + ); return MonoGCBridgeObjectKind::GC_BRIDGE_TRANSPARENT_CLASS; } @@ -555,9 +570,11 @@ OSBridge::gc_is_bridge_object (MonoObject *object) if (handle == nullptr) { #if DEBUG MonoClass *mclass = mono_object_get_class (object); - log_info (LOG_GC, "object of class %s.%s with null handle", - mono_class_get_namespace (mclass), - mono_class_get_name (mclass)); + log_info (LOG_GC, + "object of class {}.{} with null handle", + optional_string (mono_class_get_namespace (mclass)), + optional_string (mono_class_get_name (mclass)) + ); #endif return 0; } @@ -643,9 +660,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 %s to %s", 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 %s", description); + log_error (LOG_GC, "Missing monodroidAddReference method for {}", optional_string (description)); free (description); free (reffed_description); @@ -881,9 +898,11 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri #if DEBUG if (Logger::gc_spew_enabled ()) { klass = mono_object_get_class (obj); - log_error (LOG_GC, "Missing monodroidClearReferences method for object of class %s.%s", - mono_class_get_namespace (klass), - mono_class_get_name (klass)); + 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)) + ); } #endif } @@ -897,7 +916,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } } #if DEBUG - log_info (LOG_GC, "GC cleanup summary: %d objects tested - resurrecting %d.", total, alive); + log_info (LOG_GC, "GC cleanup summary: {} objects tested - resurrecting {}.", total, alive); #endif } @@ -927,10 +946,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 %d sccs and %d 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, "group %d with %d 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]; @@ -944,18 +963,20 @@ 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 [%s::%s] handle %p key_handle %p", - obj, - mono_class_get_namespace (klass), - mono_class_get_name (klass), - handle, - key_handle); + 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 + ); } } if (Util::should_log (LOG_GC)) { for (i = 0; i < num_xrefs; ++i) - log_info_nocheck (LOG_GC, "xref [%d] %d -> %d", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); + log_info_nocheck_fmt (LOG_GC, "xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); } } diff --git a/src/native/monodroid/xamarin-android-app-context.cc b/src/native/monodroid/xamarin-android-app-context.cc index 925975c336f..9ef193ddeb7 100644 --- a/src/native/monodroid/xamarin-android-app-context.cc +++ b/src/native/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 0x%llx, in mono image at index %u", 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,15 +43,15 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas { log_debug ( LOG_ASSEMBLY, - "MM: Trying to look up pointer to method '%s' (token 0x%x) in class '%s' (index %u)", - 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 {})", + 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]] { Helpers::abort_application ( - Util::monodroid_strdup_printf ( - "Internal error: invalid index for class cache (expected at most %u, got %u)", + std::format ( + "Internal error: invalid index for class cache (expected at most {}, got {})", marshal_methods_number_of_classes - 1, class_index ) @@ -78,29 +78,37 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas target_ptr = ret; } - log_debug (LOG_ASSEMBLY, "Loaded pointer to method %s (%p) (mono_image_index == %u; class_index == %u; method_token == 0x%x)", mono_method_full_name (method, true), ret, mono_image_index, class_index, method_token); + 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 + ); return; } log_fatal ( LOG_DEFAULT, - "Failed to obtain function pointer to method '%s' in class '%s'", - get_method_name (mono_image_index, method_token), - get_class_name (class_index) + "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)) ); log_fatal ( LOG_DEFAULT, - "Looked for image index %u, class index %u, method token 0x%x", + "Looked for image index {}, class index {}, method token {:x}", mono_image_index, class_index, method_token ); if (image == nullptr) { - log_fatal (LOG_DEFAULT, "Failed to load MonoImage for the assembly"); + log_fatal (LOG_DEFAULT, "Failed to load MonoImage for the assembly"sv); } else if (method == nullptr) { - log_fatal (LOG_DEFAULT, "Failed to load class from the assembly"); + log_fatal (LOG_DEFAULT, "Failed to load class from the assembly"sv); } const char *message = nullptr; @@ -109,7 +117,7 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas } Helpers::abort_application ( - message == nullptr ? "Failure to obtain marshal methods function pointer" : message + message == nullptr ? "Failure to obtain marshal methods function pointer"sv : message ); } diff --git a/src/native/monodroid/xamarin_getifaddrs.cc b/src/native/monodroid/xamarin_getifaddrs.cc index 9f071132976..23848f9910b 100644 --- a/src/native/monodroid/xamarin_getifaddrs.cc +++ b/src/native/monodroid/xamarin_getifaddrs.cc @@ -381,9 +381,9 @@ get_ifaddrs_impl (int (**getifaddrs_implementation) (struct _monodroid_ifaddrs * } if (!*getifaddrs_implementation) { - log_info (LOG_NET, "This libc does not have getifaddrs/freeifaddrs, using Xamarin's\n"); + log_info (LOG_NET, "This libc does not have getifaddrs/freeifaddrs, using Xamarin's"sv); } else { - log_info (LOG_NET, "This libc has getifaddrs/freeifaddrs\n"); + log_info (LOG_NET, "This libc has getifaddrs/freeifaddrs"sv); } } @@ -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. %s\n", 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, "Failed to bind to the netlink socket. %s\n", 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, "Failed to send netlink message. %s\n", 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, "receive buffer size == %d", 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,29 +551,29 @@ 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 == %d\n", (int)length); + log_debug (LOG_NETLINK, " length == {}", (int)length); if (length < 0) { - log_debug (LOG_NETLINK, "Failed to receive reply from netlink. %s\n", strerror (errno)); + log_debug (LOG_NETLINK, "Failed to receive reply from netlink. {}", strerror (errno)); goto cleanup; } #if DEBUG if (Util::should_log (LOG_NETLINK)) { - log_debug_nocheck (LOG_NETLINK, "response flags:"); + log_debug_nocheck (LOG_NETLINK, "response flags:"sv); if (netlink_reply.msg_flags == 0) - log_debug_nocheck (LOG_NETLINK, " [NONE]"); + log_debug_nocheck (LOG_NETLINK, " [NONE]"sv); else { if (netlink_reply.msg_flags & MSG_EOR) - log_debug_nocheck (LOG_NETLINK, " MSG_EOR"); + log_debug_nocheck (LOG_NETLINK, " MSG_EOR"sv); if (netlink_reply.msg_flags & MSG_TRUNC) - log_debug_nocheck (LOG_NETLINK, " MSG_TRUNC"); + log_debug_nocheck (LOG_NETLINK, " MSG_TRUNC"sv); if (netlink_reply.msg_flags & MSG_CTRUNC) - log_debug_nocheck (LOG_NETLINK, " MSG_CTRUNC"); + log_debug_nocheck (LOG_NETLINK, " MSG_CTRUNC"sv); if (netlink_reply.msg_flags & MSG_OOB) - log_debug_nocheck (LOG_NETLINK, " MSG_OOB"); + log_debug_nocheck (LOG_NETLINK, " MSG_OOB"sv); if (netlink_reply.msg_flags & MSG_ERRQUEUE) - log_debug_nocheck (LOG_NETLINK, " MSG_ERRQUEUE"); + log_debug_nocheck (LOG_NETLINK, " MSG_ERRQUEUE"sv); } } #endif @@ -582,21 +582,21 @@ 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: %u)\n", 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: - log_debug (LOG_NETLINK, " dumping link...\n"); + log_debug (LOG_NETLINK, " dumping link..."sv); addr = get_link_info (current_message); if (!addr || append_ifaddr (addr, ifaddrs_head, last_ifaddr) < 0) { ret = -1; goto cleanup; } - log_debug (LOG_NETLINK, " done\n"); + log_debug (LOG_NETLINK, " done"sv); break; case RTM_NEWADDR: - log_debug (LOG_NETLINK, " got an address\n"); + log_debug (LOG_NETLINK, " got an address"sv); addr = get_link_address (current_message, ifaddrs_head); if (!addr || append_ifaddr (addr, ifaddrs_head, last_ifaddr) < 0) { ret = -1; @@ -605,13 +605,13 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd break; case NLMSG_DONE: - log_debug (LOG_NETLINK, " message done\n"); + log_debug (LOG_NETLINK, " message done"sv); ret = 0; goto cleanup; break; default: - log_debug (LOG_NETLINK, " message type: %u", 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, "Unexpected IPv4 address payload length %u", 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, "Unexpected IPv6 address payload length %u", 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, "Unexpected RTA payload length %u (wanted at most %u)", 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,16 +701,16 @@ 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 == %d; sizeof sll_addr == %d; hw type == 0x%X\n", 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, "Address is too long to place in sockaddr_ll (%d > %d)", 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; } if (rta_payload_length > std::numeric_limits::max ()) { - log_info (LOG_NETLINK, "Payload length too big to fit in the address structure"); + log_info (LOG_NETLINK, "Payload length too big to fit in the address structure"sv); free (*sa); *sa = NULL; return -1; @@ -817,16 +817,15 @@ 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 %u bits (%u bytes), data length is %u 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: "); + log_debug_nocheck (LOG_NETLINK, " netmask is: "sv); for (uint32_t i = 0; i < data_length; i++) { - log_debug_nocheck (LOG_NETLINK, "%s%u", i == 0 ? " " : ".", (unsigned char)ifa->ifa_netmask->sa_data [i]); + log_debug_nocheck_fmt (LOG_NETLINK, "{}{}", i == 0 ? " "sv : "."sv, (unsigned char)ifa->ifa_netmask->sa_data [i]); } - log_debug_nocheck (LOG_NETLINK, "\n"); } } } @@ -848,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: %u", length); + log_debug (LOG_NETLINK, " address data length: {}", length); if (length <= 0) { goto error; } @@ -862,17 +861,17 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if ifa->ifa_flags = static_cast(get_interface_flags_by_index (static_cast(net_address->ifa_index), ifaddrs_head)); attribute = IFA_RTA (net_address); - log_debug (LOG_NETLINK, " reading attributes"); + log_debug (LOG_NETLINK, " reading attributes"sv); while (RTA_OK (attribute, length)) { payload_size = RTA_PAYLOAD (attribute); - log_debug (LOG_NETLINK, " attribute payload_size == %u\n", payload_size); + log_debug (LOG_NETLINK, " attribute payload_size == {}", payload_size); sa = NULL; switch (attribute->rta_type) { case IFA_LABEL: { size_t room_for_trailing_null = 0uz; - log_debug (LOG_NETLINK, " attribute type: LABEL"); + log_debug (LOG_NETLINK, " attribute type: LABEL"sv); if (payload_size > MAX_IFA_LABEL_SIZE) { payload_size = MAX_IFA_LABEL_SIZE; room_for_trailing_null = 1; @@ -893,7 +892,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if } case IFA_LOCAL: - log_debug (LOG_NETLINK, " attribute type: LOCAL"); + log_debug (LOG_NETLINK, " attribute type: LOCAL"sv); if (ifa->ifa_addr) { /* P2P protocol, set the dst/broadcast address union from the original address. * Since ifa_addr is set it means IFA_ADDRESS occured earlier and that address @@ -906,7 +905,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; case IFA_BROADCAST: - log_debug (LOG_NETLINK, " attribute type: BROADCAST"); + log_debug (LOG_NETLINK, " attribute type: BROADCAST"sv); if (ifa->_monodroid_ifa_dstaddr) { /* IFA_LOCAL happened earlier, undo its effect here */ free (ifa->_monodroid_ifa_dstaddr); @@ -916,7 +915,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; case IFA_ADDRESS: - log_debug (LOG_NETLINK, " attribute type: ADDRESS"); + log_debug (LOG_NETLINK, " attribute type: ADDRESS"sv); if (ifa->ifa_addr) { /* Apparently IFA_LOCAL occured earlier and we have a P2P connection * here. IFA_LOCAL carries the destination address, move it there @@ -928,23 +927,23 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; case IFA_UNSPEC: - log_debug (LOG_NETLINK, " attribute type: UNSPEC"); + log_debug (LOG_NETLINK, " attribute type: UNSPEC"sv); break; case IFA_ANYCAST: - log_debug (LOG_NETLINK, " attribute type: ANYCAST"); + log_debug (LOG_NETLINK, " attribute type: ANYCAST"sv); break; case IFA_CACHEINFO: - log_debug (LOG_NETLINK, " attribute type: CACHEINFO"); + log_debug (LOG_NETLINK, " attribute type: CACHEINFO"sv); break; case IFA_MULTICAST: - log_debug (LOG_NETLINK, " attribute type: MULTICAST"); + log_debug (LOG_NETLINK, " attribute type: MULTICAST"sv); break; default: - log_debug (LOG_NETLINK, " attribute type: %u", attribute->rta_type); + log_debug (LOG_NETLINK, " attribute type: {}", attribute->rta_type); break; } @@ -960,10 +959,10 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if /* glibc stores the associated interface name in the address if IFA_LABEL never occured */ if (!ifa->ifa_name) { char *name = get_interface_name_by_index (static_cast(net_address->ifa_index), ifaddrs_head); - log_debug (LOG_NETLINK, " address has no name/label, getting one from interface\n"); + 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: %s\n", 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,13 +1016,13 @@ get_link_info (const struct nlmsghdr *message) goto error; } if (Util::should_log (LOG_NETLINK)) { - log_debug_nocheck (LOG_NETLINK, " interface name (payload length: %d; string length: %d)\n", RTA_PAYLOAD (attribute), strlen (ifa->ifa_name)); - log_debug_nocheck (LOG_NETLINK, " %s\n", ifa->ifa_name); + 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)); } break; case IFLA_BROADCAST: - log_debug (LOG_NETLINK, " interface broadcast (%d bytes)\n", 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; } @@ -1031,7 +1030,7 @@ get_link_info (const struct nlmsghdr *message) break; case IFLA_ADDRESS: - log_debug (LOG_NETLINK, " interface address (%d bytes)\n", 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; } @@ -1040,7 +1039,7 @@ get_link_info (const struct nlmsghdr *message) default: #if DEBUG - log_debug (LOG_NETLINK, " rta_type: "); + log_debug (LOG_NETLINK, " rta_type: "sv); print_ifla_name (attribute->rta_type); #endif // DEBUG break; @@ -1048,7 +1047,7 @@ get_link_info (const struct nlmsghdr *message) attribute = RTA_NEXT (attribute, length); } - log_debug (LOG_NETLINK, "link flags: 0x%X", ifa->ifa_flags); + log_debug (LOG_NETLINK, "link flags: {:X}", ifa->ifa_flags); return ifa; error: @@ -1143,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, "Unknown ifla->name: unknown id %d\n", id); + log_info_nocheck_fmt (LOG_NETLINK, "Unknown ifla->name: unknown id {}", id); break; } @@ -1151,7 +1150,7 @@ print_ifla_name (int id) i++; continue; } - log_info_nocheck (LOG_NETLINK, "ifla->name: %s (%d)\n", iflas [i].name, iflas [i].value); + log_info_nocheck_fmt (LOG_NETLINK, "ifla->name: {} ({})", optional_string (iflas [i].name), iflas [i].value); break; } } @@ -1166,7 +1165,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) char *msg, *tmp; if (!list) { - log_info_nocheck (LOG_NETLINK, "monodroid-net", "No list to print in %s", __FUNCTION__); + log_info_nocheck_fmt (LOG_NETLINK, "No list to print in {}", __FUNCTION__); return; } @@ -1181,7 +1180,7 @@ print_address_list (const char title[], struct _monodroid_ifaddrs *list) cur = cur->ifa_next; } - log_info_nocheck (LOG_NETLINK, "%s: %s", title, msg ? msg : "[no addresses]"); + log_info_nocheck_fmt (LOG_NETLINK, "{}: {}", title, optional_string (msg, "[no addresses]")); free (msg); } #endif diff --git a/src/native/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/pinvoke-override/pinvoke-override-api-impl.hh index 36523f092a9..259a0d5c879 100644 --- a/src/native/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/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 '%s' not loaded, p/invoke '%s' 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 '%s' 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 '%s' not found in shared library '%s', 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; } @@ -60,7 +60,7 @@ namespace xamarin::android { return nullptr; } - log_debug (LOG_ASSEMBLY, "Caching p/invoke entry %s @ %s", library_name.c_str (), entrypoint_name.c_str ()); + log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); (*api_map)[entrypoint_name] = entry_handle; return entry_handle; } @@ -73,15 +73,15 @@ namespace xamarin::android { 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 + /* expected */ &expected_null, + /* desired */ &entry_handle, + /* weak */ false, + /* success_memorder */ __ATOMIC_ACQUIRE, + /* failure_memorder */ __ATOMIC_RELAXED ); if (already_loaded) { - log_debug (LOG_ASSEMBLY, "Entry '%s' from library '%s' 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, "Internal error: null entry in p/invoke map for key '%s'", 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/pinvoke-override/precompiled.cc b/src/native/pinvoke-override/precompiled.cc index 1c84095080a..29ac736e433 100644 --- a/src/native/pinvoke-override/precompiled.cc +++ b/src/native/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 '%s @ %s' (hash: 0x%zx) not found in compile-time map.", library_name, entrypoint_name, entrypoint_hash); - log_fatal (LOG_ASSEMBLY, "compile-time map contents:"); + 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'%s'=%p (hash: 0x%zx)", 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, - Util::monodroid_strdup_printf ( - "Failure handling a p/invoke request for '%s'@'%s'", - entrypoint_name, - library_name + std::format ( + "Failure handling a p/invoke request for '{}'@'{}'", + 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 '%s' from shared library '%s'", 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 '%s' in library '%s' 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/runtime-base/android-system.cc b/src/native/runtime-base/android-system.cc index 44745a7f34f..d3c8b2c56e4 100644 --- a/src/native/runtime-base/android-system.cc +++ b/src/native/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 (%u)", 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, "Buffer to store system property may be too small, will copy only %u 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, "Trying to get property from %s", 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, "Property '%s' from %s has value '%s'.", 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, "Creating public update directory: `%s`", 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, "Trying to load shared library '%s'", 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, "Shared library '%s' 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, "Failed to load shared library '%s'. %s", 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, "Unsupported '%s' value '%s'.", 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, "Overriding max JNI Global Reference count to %i", 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, "(Debug) Failed to set environment variable: %s", 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, "Failed to stat the environment override file %s: %s", 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, "Failed to open the environment override file %s: %s", 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, "Failed to read the environment override file %s: %s", 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, "Invalid format of the environment override file %s: 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, "Malformed header of the environment override file %s: 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, "Malformed header of the environment override file %s: 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, "Malformed environment override file %s: 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, "Malformed environment override file %s: name at offset %lu 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, "Setting environment variable from the override file %s: '%s' = '%s'", 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,18 +602,18 @@ AndroidSystem::setup_environment () noexcept } if (aotMode != MonoAotMode::MONO_AOT_MODE_LAST) { - log_debug (LOG_DEFAULT, "Mono AOT mode: %s", mono_aot_mode_name); + log_debug (LOG_DEFAULT, "Mono AOT mode: {}", mono_aot_mode_name); } else { if (!is_interpreter_enabled ()) { - log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: %s", 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"); + log_warn (LOG_DEFAULT, "Mono AOT mode: interpreter"sv); } } } if (application_config.environment_variable_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries (%u)", 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,21 +629,21 @@ AndroidSystem::setup_environment () noexcept var_value = ""; #if defined (DEBUG) - log_info (LOG_DEFAULT, "Setting environment variable '%s' to '%s'", 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, "Failed to set environment variable: %s", 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."); + log_debug (LOG_DEFAULT, "Loading environment from override directories."sv); for (const char *od : override_dirs) { if (od == nullptr) { continue; } std::unique_ptr env_override_file {Util::path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; - log_debug (LOG_DEFAULT, "%s", env_override_file.get ()); + log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); if (Util::file_exists (env_override_file.get ())) { - log_debug (LOG_DEFAULT, "Loading %s", 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, "Checking if libmonodroid was unpacked to %s", 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, "%s 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, "Native libs extracted to %s, 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); } } @@ -685,13 +685,13 @@ 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"); + log_debug (LOG_DEFAULT, "Setting up for DSO lookup in app data directories"sv); AndroidSystem::app_lib_directories = std::span (single_app_lib_directory); AndroidSystem::app_lib_directories [0] = Util::strdup_new (appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: %s", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + 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"); + 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 @@ -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: %s", app_lib_directories[index]); + log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: {}", app_lib_directories[index]); index++; } diff --git a/src/native/runtime-base/internal-pinvokes.hh b/src/native/runtime-base/internal-pinvokes.hh index b73e390cccf..b8e7a4ae424 100644 --- a/src/native/runtime-base/internal-pinvokes.hh +++ b/src/native/runtime-base/internal-pinvokes.hh @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/src/native/runtime-base/logger.cc b/src/native/runtime-base/logger.cc index 5c4be349fae..dcc93d08d7e 100644 --- a/src/native/runtime-base/logger.cc +++ b/src/native/runtime-base/logger.cc @@ -12,6 +12,7 @@ #include "android-system.hh" #include "cpp-util.hh" +#include "log_level.hh" #include "logger.hh" #include "shared-constants.hh" #include "util.hh" @@ -27,8 +28,13 @@ namespace { FILE *f; if (path && access (path, W_OK) < 0) { - log_warn (category, "Could not open path '%s' for logging (\"%s\"). Using '%s/%s' instead.", - path, strerror (errno), override_dir, filename); + log_warn (category, + "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", + optional_string (path), + strerror (errno), + optional_string (override_dir), + optional_string (filename) + ); path = NULL; } @@ -45,7 +51,7 @@ namespace { if (f) { Util::set_world_accessable (path); } else { - log_warn (category, "Could not open path '%s' for logging: %s", path, strerror (errno)); + log_warn (category, "Could not open path '{}' for logging: {}", optional_string (path), strerror (errno)); } free (p); @@ -71,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, "Invalid debugger log level value '%s', 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, "Debugger log level value is higher than the maximum of %u, 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/runtime-base/monodroid-dl.hh b/src/native/runtime-base/monodroid-dl.hh index 14455578f0e..4c3df81e077 100644 --- a/src/native/runtime-base/monodroid-dl.hh +++ b/src/native/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 0x%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, "Looking for hash 0x%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, "Mono '%s' component requested but not packaged, ignoring", label); + log_info (LOG_ASSEMBLY, "Mono '{}' component requested but not packaged, ignoring", label); return true; } @@ -145,12 +145,12 @@ namespace xamarin::android::internal static void* monodroid_dlopen (const char *name, int flags, char **err, bool prefer_aot_cache) noexcept { if (name == nullptr) { - log_warn (LOG_ASSEMBLY, "monodroid_dlopen got a null name. This is not supported in NET+"); + log_warn (LOG_ASSEMBLY, "monodroid_dlopen got a null name. This is not supported in NET+"sv); return nullptr; } hash_t name_hash = xxhash::hash (name, strlen (name)); - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '%s' is 0x%zx", 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, "monodroid_dlopen: hash match %sfound, DSO name is '%s'", dso == nullptr ? "not " : "", dso == nullptr ? "" : 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, "Request to load '%s' 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/runtime-base/strings.hh b/src/native/runtime-base/strings.hh index 74fe498de4c..65f6603e501 100644 --- a/src/native/runtime-base/strings.hh +++ b/src/native/runtime-base/strings.hh @@ -156,7 +156,7 @@ namespace xamarin::android::internal } if (!can_access (start_index)) { - log_error (LOG_DEFAULT, "Cannot convert string to integer, index %u is out of range", start_index); + log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); return false; } @@ -180,17 +180,17 @@ namespace xamarin::android::internal } if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, "Value %s is out of range of this type (%lld..%llu)", 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, "Value %s does not represent a base %d integer", 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, "Value %s has non-numeric characters at the end", s); + log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); return false; } diff --git a/src/native/runtime-base/timing-internal.cc b/src/native/runtime-base/timing-internal.cc index eaaee8c17ef..6efcfdae461 100644 --- a/src/native/runtime-base/timing-internal.cc +++ b/src/native/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: %u:%u::%u", 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: %u:%u::%u", 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: %u:%u::%u", sec, ms, ns); + log_info_nocheck (LOG_TIMING, " [2/7] Managed to Java lookup: {}:{}::{}", sec, ms, ns); } diff --git a/src/native/runtime-base/timing-internal.hh b/src/native/runtime-base/timing-internal.hh index 4e896c8fc94..d87595ac9bd 100644 --- a/src/native/runtime-base/timing-internal.hh +++ b/src/native/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 %zu to %zu", 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 force_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 '%s'", method_name); + log_warn (LOG_TIMING, "Invalid event index passed to method '{}'", method_name); return false; } diff --git a/src/native/runtime-base/timing.hh b/src/native/runtime-base/timing.hh index 815e256252c..191ec55df2f 100644 --- a/src/native/runtime-base/timing.hh +++ b/src/native/runtime-base/timing.hh @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -69,11 +70,9 @@ namespace xamarin::android // 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. -#define TIMING_FORMAT "; elapsed: %lis:%lu::%lu" - class Timing { - static constexpr char MESSAGE_FORMAT[] = "%s" TIMING_FORMAT; + static inline constexpr std::string_view MESSAGE_FORMAT { "{}; elapsed: {}:{}::{}" }; public: static constexpr size_t DEFAULT_POOL_SIZE = 16uz; @@ -94,14 +93,14 @@ namespace xamarin::android { timing_diff diff (period); - log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT, message == nullptr ? "" : 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, MESSAGE_FORMAT, message == nullptr ? "" : 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 @@ -147,20 +146,5 @@ namespace xamarin::android size_t sequence_pool_size; xamarin::android::mutex sequence_lock; }; - - // This is a hack to avoid having to allocate memory when rendering messages that use additional - // format placeholders on the caller side. Memory allocation would be necessary since we append - // the standard timing suffix to every message printed. Using a variadic macro allows us to - // compose a call with all the elements present and make the composition compile-time. - // - // It could be done with template packs but that would result in extra code generated whenever a - // call with a different set of parameters would be made, plus the code to implement that would - // be a bit verbose and unwieldy, so we will stick to this simple method. -#define TIMING_DO_LOG(_level, _category_, ...) ::log_ ## _level ## _nocheck ((_category_), __VA_ARGS__) - -#define TIMING_LOG_INFO(__period__, __format__, ...) { \ - timing_diff diff ((__period__)); \ - TIMING_DO_LOG (info, LOG_TIMING, __format__ TIMING_FORMAT, __VA_ARGS__, diff.sec, diff.ms, diff.ns); \ - } } #endif // __TIMING_HH diff --git a/src/native/runtime-base/util.cc b/src/native/runtime-base/util.cc index 7a58a2836c1..e0c568124ea 100644 --- a/src/native/runtime-base/util.cc +++ b/src/native/runtime-base/util.cc @@ -149,7 +149,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 '%s'. %s", dir, std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); } umask (m); } @@ -197,7 +197,7 @@ Util::set_world_accessable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"%s\", 0664) failed: %s", path, strerror (errno)); + log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); } } @@ -210,7 +210,7 @@ Util::set_user_executable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"%s\") failed: %s", path, strerror (errno)); + log_error (LOG_DEFAULT, "chmod(\"{}\") failed: {}", path, strerror (errno)); } } @@ -240,12 +240,12 @@ bool Util::file_copy (const char *to, const char *from) { if (to == nullptr || *to == '\0') { - log_error (LOG_DEFAULT, "Util::file_copy: `to` parameter must not be null or empty"); + log_error (LOG_DEFAULT, "Util::file_copy: `to` parameter must not be null or empty"sv); return false; } if (from == nullptr || *from == '\0') { - log_error (LOG_DEFAULT, "Util::file_copy: `from` parameter must not be null or empty"); + log_error (LOG_DEFAULT, "Util::file_copy: `from` parameter must not be null or empty"sv); return false; } @@ -297,7 +297,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 %s: %s", filename, strerror (errno)); + log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); return nullptr; } diff --git a/src/native/runtime-base/util.hh b/src/native/runtime-base/util.hh index 97db495dbea..986f7f2e49a 100644 --- a/src/native/runtime-base/util.hh +++ b/src/native/runtime-base/util.hh @@ -79,7 +79,7 @@ namespace xamarin::android { struct stat sbuf; if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, "Failed to stat file '%s': %s", file_name, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to stat file '{}': {}", file_name, std::strerror (errno)); return std::nullopt; } @@ -90,7 +90,7 @@ namespace xamarin::android { int fd = openat (dirfd, file_name, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, "Failed to open file '%s' for reading: %s", file_name, std::strerror (errno)); + log_error (LOG_ASSEMBLY, "Failed to open file '{}' for reading: {}", file_name, std::strerror (errno)); return std::nullopt; } diff --git a/src/native/shared/CMakeLists.txt b/src/native/shared/CMakeLists.txt index 958c474f63c..75f4b0c4616 100644 --- a/src/native/shared/CMakeLists.txt +++ b/src/native/shared/CMakeLists.txt @@ -1,21 +1,11 @@ set(LIB_NAME xa-shared-bits) set(LIB_ALIAS xa::shared) -set(LIB_NAME_NO_ABI ${LIB_NAME}-no-abi) -set(LIB_ALIAS_NO_ABI ${LIB_ALIAS}-no-abi) - -set(XA_SHARED_CXX_ABI_SOURCES - cxx-abi/string.cc - cxx-abi/terminate.cc - ${REPO_ROOT_DIR}/src-ThirdParty/llvm/verbose_abort.cpp -) - set(XA_SHARED_SOURCES helpers.cc log_functions.cc - new_delete.cc ) -add_clang_check_sources("${XA_SHARED_SOURCES};${XA_SHARED_CXX_ABI_SOURCES}") +add_clang_check_sources("${XA_SHARED_SOURCES};") set(XXHASH_DIR "${EXTERNAL_DIR}/xxHash") set(CONSTEXPR_XXH3_DIR "${EXTERNAL_DIR}/constexpr-xxh3") @@ -30,15 +20,6 @@ add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) set_static_library_suffix(${LIB_NAME}) -add_library( - ${LIB_NAME_NO_ABI} - STATIC - ${XA_SHARED_SOURCES} -) -add_library(${LIB_ALIAS_NO_ABI} ALIAS ${LIB_NAME_NO_ABI}) - -set_static_library_suffix(${LIB_NAME_NO_ABI}) - macro(lib_target_options TARGET_NAME) target_include_directories( ${TARGET_NAME} @@ -81,4 +62,3 @@ macro(lib_target_options TARGET_NAME) endmacro() lib_target_options(${LIB_NAME}) -lib_target_options(${LIB_NAME_NO_ABI}) diff --git a/src/native/shared/cpp-util.hh b/src/native/shared/cpp-util.hh index a4546971a29..bf9b01bcadf 100644 --- a/src/native/shared/cpp-util.hh +++ b/src/native/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 ); @@ -142,7 +142,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: %s:%u ('%s')", 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/shared/cxx-abi/string.cc b/src/native/shared/cxx-abi/string.cc deleted file mode 100644 index 30d528e14ac..00000000000 --- a/src/native/shared/cxx-abi/string.cc +++ /dev/null @@ -1,12 +0,0 @@ -// -// Defining the macro will make the the explicit instantations below truely hidden -// -#define _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS - -#include - -_LIBCPP_BEGIN_NAMESPACE_STD - -template class __attribute__ ((__visibility__("hidden"))) basic_string; - -_LIBCPP_END_NAMESPACE_STD diff --git a/src/native/shared/cxx-abi/terminate.cc b/src/native/shared/cxx-abi/terminate.cc deleted file mode 100644 index 04dc890fb61..00000000000 --- a/src/native/shared/cxx-abi/terminate.cc +++ /dev/null @@ -1,17 +0,0 @@ -// -// Simple implementation of std::terminate() for Xamarin.Android -// -// Does NOT support terminate handlers, since we don't use them. -// -#include -#include - -#include "helpers.hh" - -namespace std { - [[noreturn]] void - terminate () noexcept - { - xamarin::android::Helpers::abort_application ("std::terminate() called. Aborting."); - } -} diff --git a/src/native/shared/helpers.cc b/src/native/shared/helpers.cc index bf8a8bd5339..9638b16ebd5 100644 --- a/src/native/shared/helpers.cc +++ b/src/native/shared/helpers.cc @@ -3,7 +3,7 @@ #include #include "helpers.hh" -#include "java-interop-logger.h" +#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, "{}", message); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -35,7 +35,7 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - "Abort at %s:%u:%u ('%s')", + "Abort at {}:{}:{} ('%s')", file_name, sloc.line (), sloc.column (), diff --git a/src/native/shared/helpers.hh b/src/native/shared/helpers.hh index 3c6c16ca6a3..62aeea9e00e 100644 --- a/src/native/shared/helpers.hh +++ b/src/native/shared/helpers.hh @@ -3,12 +3,21 @@ #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: @@ -46,10 +55,46 @@ namespace xamarin::android [[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; + } } #endif // __HELPERS_HH diff --git a/src/native/shared/log_functions.cc b/src/native/shared/log_functions.cc index 114bc0186e7..c6d61f54d0d 100644 --- a/src/native/shared/log_functions.cc +++ b/src/native/shared/log_functions.cc @@ -4,7 +4,7 @@ #include #include "java-interop-logger.h" -#include "log_types.hh" +#include "log_level.hh" // Must match the same ordering as LogCategories static constexpr std::array log_names = { diff --git a/src/native/shared/log_level.hh b/src/native/shared/log_level.hh new file mode 100644 index 00000000000..fc7a7566910 --- /dev/null +++ b/src/native/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/shared/log_types.hh b/src/native/shared/log_types.hh index b0ed20018d9..66b1cae5097 100644 --- a/src/native/shared/log_types.hh +++ b/src/native/shared/log_types.hh @@ -1,35 +1,112 @@ -#if !defined(LOG_LEVEL_HH) -#define LOG_LEVEL_HH +#pragma once #include +#include +#include +#include #include "java-interop-logger.h" +#include "log_level.hh" -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 - }; +// 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; -#endif // ndef LOG_LEVEL_HH diff --git a/src/native/shared/new_delete.cc b/src/native/shared/new_delete.cc deleted file mode 100644 index 2293dddca10..00000000000 --- a/src/native/shared/new_delete.cc +++ /dev/null @@ -1,87 +0,0 @@ -#include - -#include "helpers.hh" - -namespace std -{ - struct nothrow_t {}; - extern const nothrow_t nothrow; -} - -#include "java-interop-util.h" - -static void* -do_alloc (size_t size) -{ - return ::malloc (size == 0 ? 1 : size); -} - -__attribute__((__weak__)) -void* -operator new (size_t size) -{ - void* p = do_alloc (size); - if (p == nullptr) { - xamarin::android::Helpers::abort_application ("Out of memory in the `new` operator"); - } - - return p; -} - -void* -operator new (size_t size, const std::nothrow_t&) noexcept -{ - return do_alloc (size); -} - -__attribute__((__weak__)) -void* -operator new[] (size_t size) -{ - return ::operator new (size); -} - -void* -operator new[] (size_t size, const std::nothrow_t&) noexcept -{ - return do_alloc (size); -} - -__attribute__((__weak__)) -void -operator delete (void* ptr) noexcept -{ - if (ptr) - ::free (ptr); -} - -void -operator delete (void* ptr, const std::nothrow_t&) -{ - ::operator delete (ptr); -} - -void -operator delete (void* ptr, size_t) noexcept -{ - ::operator delete (ptr); -} - -__attribute__((__weak__)) -void -operator delete[] (void* ptr) noexcept -{ - ::operator delete (ptr); -} - -void -operator delete[] (void* ptr, const std::nothrow_t&) noexcept -{ - ::operator delete[] (ptr); -} - -void -operator delete[] (void* ptr, size_t) noexcept -{ - ::operator delete[] (ptr); -} diff --git a/src/native/tracing/CMakeLists.txt b/src/native/tracing/CMakeLists.txt index cc91cb2fa78..558b3513659 100644 --- a/src/native/tracing/CMakeLists.txt +++ b/src/native/tracing/CMakeLists.txt @@ -62,7 +62,7 @@ target_link_options( target_link_libraries( ${LIB_NAME} PRIVATE - xa::shared-no-abi + xa::shared xa::unwind xa::runtime-base xa::java-interop diff --git a/src/native/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/xamarin-debug-app-helper/debug-app-helper.cc index e083f905ab4..e64c42750c8 100644 --- a/src/native/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/xamarin-debug-app-helper/debug-app-helper.cc @@ -14,33 +14,17 @@ #include "debug-app-helper.hh" #include "shared-constants.hh" #include "jni-wrappers.hh" +#include "log_types.hh" using namespace xamarin::android; using namespace xamarin::android::internal; -#undef DO_LOG -#undef log_info - -void log_info (LogCategories category, const char *format, ...); -void log_warn (LogCategories category, const char *format, ...); -void log_error (LogCategories category, const char *format, ...); -void log_fatal (LogCategories category, const char *format, ...); - static void copy_file_to_internal_location (char *to_dir, char *from_dir, char *file); static void copy_native_libraries_to_internal_location (); static const char* get_libmonosgen_path (); bool maybe_load_library (const char *path); -#define DO_LOG(_level_,_tag_,_format_,_args_) \ - va_start ((_args_), (_format_)); \ - __android_log_vprint ((_level_), (_tag_), (_format_), (_args_)); \ - va_end ((_args_)); - -static constexpr char TAG[] = "debug-app-helper"; - -unsigned int log_categories = LOG_DEFAULT | LOG_ASSEMBLY; - JNIEXPORT jint JNICALL JNI_OnLoad ([[maybe_unused]] JavaVM *vm, [[maybe_unused]] void *reserved) { @@ -64,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: %s", AndroidSystem::get_runtime_libdir ()); + log_warn (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); } const char *monosgen_path = get_libmonosgen_path (); @@ -89,8 +73,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) if (!from_file || !Util::file_exists (from_file)) break; - log_warn (LOG_DEFAULT, "Copying file `%s` from external location `%s` to internal location `%s`", - file, from_dir, to_dir); + log_warn (LOG_DEFAULT, + "Copying file `{}` from external location `{}` to internal location `{}`", + optional_string (file), + optional_string (from_dir), + optional_string (to_dir) + ); to_file = Util::path_combine (to_dir, file); if (!to_file) @@ -98,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 `%s`: %s", 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 `%s` to `%s`: %s", 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; } @@ -122,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: `%s`", 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: `%s`", 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: `%s`", 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: `%s`", 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); } @@ -154,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: %s", 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: %s", libmonoso); + log_info (LOG_DEFAULT, "Mono runtime found at: {}", optional_string (libmonoso)); return true; } delete[] libmonoso; @@ -208,34 +196,34 @@ 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: %s -> %s", link, libmonoso); + log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", optional_string (link), optional_string (libmonoso)); unlink (link); result = symlink (libmonoso, link); } if (result != 0) - log_warn (LOG_DEFAULT, "symlink failed with errno=%i %s", errno, strerror (errno)); + log_warn (LOG_DEFAULT, "symlink failed with errno={} {}", errno, strerror (errno)); } delete[] libmonoso; libmonoso = link; } - log_warn (LOG_DEFAULT, "Trying to load sgen from: %s", libmonoso != nullptr ? libmonoso : ""); + log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", optional_string (libmonoso)); 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 '%s'. 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) continue; - log_fatal (LOG_DEFAULT, " %s", od); + log_fatal (LOG_DEFAULT, " {}", optional_string (od)); } for (const char *app_lib_dir : AndroidSystem::app_lib_directories) { - log_fatal (LOG_DEFAULT, " %s", app_lib_dir); + log_fatal (LOG_DEFAULT, " {}", optional_string (app_lib_dir)); } Helpers::abort_application ( @@ -245,54 +233,3 @@ get_libmonosgen_path () return libmonoso; } - -void -log_debug_nocheck ([[maybe_unused]] LogCategories category, const char *format, ...) -{ - va_list args; - - if ((log_categories & category) == 0) - return; - - DO_LOG (ANDROID_LOG_DEBUG, TAG, format, args); -} - -void -log_info ([[maybe_unused]] LogCategories category, const char *format, ...) -{ - va_list args; - - DO_LOG (ANDROID_LOG_INFO, TAG, format, args); -} - -void -log_info_nocheck ([[maybe_unused]] LogCategories category, const char *format, ...) -{ - va_list args; - - if ((log_categories & category) == 0) - return; - - DO_LOG (ANDROID_LOG_INFO, TAG, format, args); -} - -void log_error ([[maybe_unused]] LogCategories category, const char* format, ...) -{ - va_list args; - - DO_LOG (ANDROID_LOG_ERROR, TAG, format, args); -} - -void log_fatal ([[maybe_unused]] LogCategories category, const char* format, ...) -{ - va_list args; - - DO_LOG (ANDROID_LOG_FATAL, TAG, format, args); -} - -void log_warn ([[maybe_unused]] LogCategories category, const char* format, ...) -{ - va_list args; - - DO_LOG (ANDROID_LOG_WARN, TAG, format, args); -}