diff --git a/samples/NativeAOT/NativeAOT.csproj b/samples/NativeAOT/NativeAOT.csproj index d16ef4b8056..b971a851f9e 100644 --- a/samples/NativeAOT/NativeAOT.csproj +++ b/samples/NativeAOT/NativeAOT.csproj @@ -12,4 +12,8 @@ true - \ No newline at end of file + + + + + diff --git a/samples/NativeAOT/environment.txt b/samples/NativeAOT/environment.txt new file mode 100644 index 00000000000..1fbd68e71b6 --- /dev/null +++ b/samples/NativeAOT/environment.txt @@ -0,0 +1 @@ +naot.system.property=testing 1 2 3 diff --git a/samples/NativeAOT/run.sh b/samples/NativeAOT/run.sh index bf6e8379d15..1f815130abd 100755 --- a/samples/NativeAOT/run.sh +++ b/samples/NativeAOT/run.sh @@ -19,7 +19,7 @@ fi adb uninstall "${PACKAGE}" || true adb install -r -d --no-streaming --no-fastdeploy "${APK}" -#adb shell setprop debug.mono.log default,assembly,timing=bare +adb shell setprop debug.mono.log default,assembly,timing=bare adb logcat -G 128M adb logcat -c adb shell am start -S --user "0" -a "android.intent.action.MAIN" -c "android.intent.category.LAUNCHER" -n "${PACKAGE}/${ACTIVITY}" -W diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index 0120ff02aba..43372363cfd 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -72,6 +72,9 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. clang++ llvm-objcopy + + false + true - - + - + + + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 89f08f48fca..6e8c70e7d1d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -159,11 +159,11 @@ public void BasicApplicationPublishReadyToRun (bool isComposite, string rid) var helper = new ArchiveAssemblyHelper (apk, true); var abi = MonoAndroidHelper.RidToAbi (rid); Assert.IsTrue (helper.Exists ($"assemblies/{abi}/{assemblyName}.dll"), $"{assemblyName}.dll should exist in apk!"); - + using var stream = helper.ReadEntry ($"assemblies/{assemblyName}.dll"); stream.Position = 0; using var peReader = new System.Reflection.PortableExecutable.PEReader (stream); - Assert.IsTrue (peReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory.Size > 0, + Assert.IsTrue (peReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory.Size > 0, $"ReadyToRun image not found in {assemblyName}.dll! ManagedNativeHeaderDirectory should not be empty!"); } @@ -193,9 +193,7 @@ public void NativeAOT () ]; string [] nativeaot_files = [ $"lib/arm64-v8a/lib{proj.ProjectName}.so", - "lib/arm64-v8a/libc++_shared.so", $"lib/x86_64/lib{proj.ProjectName}.so", - "lib/x86_64/libc++_shared.so", ]; var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index 7392418c5d8..3438f098bdb 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -332,10 +332,21 @@ protected override void Construct (LlvmIrModule module) module.Add (envVars); module.AddGlobalVariable ("app_environment_variable_contents", envVarsBlob, LlvmIrVariableOptions.GlobalConstant); - var sysProps = new LlvmIrGlobalVariable (systemProperties ?? new SortedDictionary(), "app_system_properties") { + // We reuse the same structure as for environment variables, there's no point in adding a new, identical, one + var sysPropsBlob = new LlvmIrStringBlob (); + List> appSysProps = LlvmIrHelpers.MakeEnvironmentVariableList ( + Log, + systemProperties, + sysPropsBlob, + appEnvironmentVariableStructureInfo + ); + + var sysProps = new LlvmIrGlobalVariable (appSysProps, "app_system_properties") { Comment = " System properties defined by the application", + Options = LlvmIrVariableOptions.GlobalConstant, }; - module.Add (sysProps, stringGroupName: "sysprop", stringGroupComment: " System properties name:value pairs"); + module.Add (sysProps); + module.AddGlobalVariable ("app_system_property_contents", sysPropsBlob, LlvmIrVariableOptions.GlobalConstant); DsoCacheState dsoState = InitDSOCache (); var app_cfg = new ApplicationConfigCLR { @@ -347,7 +358,7 @@ protected override void Construct (LlvmIrModule module) number_of_runtime_properties = (uint)(runtimeProperties == null ? 0 : runtimeProperties.Count), package_naming_policy = (uint)PackageNamingPolicy, environment_variable_count = (uint)(environmentVariables == null ? 0 : environmentVariables.Count), - system_property_count = (uint)(systemProperties == null ? 0 : systemProperties.Count * 2), + system_property_count = (uint)(appSysProps.Count), number_of_assemblies_in_apk = (uint)NumberOfAssembliesInApk, number_of_shared_libraries = (uint)NativeLibraries.Count, bundled_assembly_name_width = (uint)BundledAssemblyNameWidth, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAotEnvironmentNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAotEnvironmentNativeAssemblyGenerator.cs index ad80bb9c03d..210512de964 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAotEnvironmentNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAotEnvironmentNativeAssemblyGenerator.cs @@ -28,6 +28,8 @@ protected override void Construct (LlvmIrModule module) SortedDictionary? systemProperties = null; if (envBuilder.SystemProperties.Count > 0) { systemProperties = new (envBuilder.SystemProperties, StringComparer.Ordinal); + } else { + systemProperties = new (StringComparer.Ordinal); } var envVarsBlob = new LlvmIrStringBlob (); @@ -47,6 +49,25 @@ protected override void Construct (LlvmIrModule module) }; module.Add (envVars); module.AddGlobalVariable ("__naot_android_app_environment_variable_contents", envVarsBlob, LlvmIrVariableOptions.GlobalConstant); + + // We reuse the same structure as for environment variables, there's no point in adding a new, identical, one + var sysPropsBlob = new LlvmIrStringBlob (); + List> appSysProps = LlvmIrHelpers.MakeEnvironmentVariableList ( + Log, + systemProperties, + sysPropsBlob, + appEnvironmentVariableStructureInfo + ); + + var sysPropsCount = new LlvmIrGlobalVariable ((uint)appSysProps.Count, "__naot_android_app_system_property_count"); + module.Add (sysPropsCount); + + var sysProps = new LlvmIrGlobalVariable (appSysProps, "__naot_android_app_system_properties") { + Comment = " System properties defined by the application", + Options = LlvmIrVariableOptions.GlobalConstant, + }; + module.Add (sysProps); + module.AddGlobalVariable ("__naot_android_app_system_property_contents", sysPropsBlob, LlvmIrVariableOptions.GlobalConstant); } void MapStructures (LlvmIrModule module) diff --git a/src/native/clr/include/host/host-environment-clr.hh b/src/native/clr/include/host/host-environment-clr.hh new file mode 100644 index 00000000000..c06ec3f8c71 --- /dev/null +++ b/src/native/clr/include/host/host-environment-clr.hh @@ -0,0 +1,4 @@ +#pragma once + +#include +#include diff --git a/src/native/clr/include/host/host-environment.hh b/src/native/clr/include/host/host-environment.hh new file mode 100644 index 00000000000..fd3a5f16e1b --- /dev/null +++ b/src/native/clr/include/host/host-environment.hh @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include +#include + +#include + +struct AppEnvironmentVariable; + +namespace xamarin::android { + class HostEnvironment + { + public: + static void init () noexcept; + + [[gnu::flatten, gnu::always_inline]] + static void set_variable (const char *name, const char *value) noexcept + { + log_debug (LOG_DEFAULT, " Variable {} = '{}'", optional_string (name), optional_string (value)); + if (::setenv (name, value, 1) < 0) { + log_warn (LOG_DEFAULT, "Failed to set environment variable '{}': {}", name, ::strerror (errno)); + } + } + + [[gnu::flatten, gnu::always_inline]] + static void set_variable (std::string_view const& name, std::string_view const& value) noexcept + { + set_variable (name.data (), value.data ()); + } + + [[gnu::flatten, gnu::always_inline]] + static void set_system_property (const char *name, const char *value) noexcept + { + // TODO: should we **actually** try to set the system property here? Would that even work? Needs testing + log_debug (LOG_DEFAULT, " System property {} = '{}'", optional_string (name), optional_string (value)); + } + + [[gnu::flatten, gnu::always_inline]] + static auto lookup_system_property (std::string_view const& name, size_t &value_len, + uint32_t const count, AppEnvironmentVariable const (&entries)[], + const char (&contents)[]) noexcept -> const char* + { + if (count == 0) { + return nullptr; + } + + for (size_t i = 0; i < count; i++) { + AppEnvironmentVariable const& sys_prop = entries[i]; + const char *prop_name = &contents[sys_prop.name_index]; + if (name.compare (prop_name) != 0) { + continue; + } + + const char *prop_value = &contents[sys_prop.value_index]; + value_len = strlen (prop_value); + return prop_value; + } + + return nullptr; + } + + template [[gnu::flatten, gnu::always_inline]] + static void set_values (uint32_t const& count, AppEnvironmentVariable const (&entries)[], const char (&contents)[]) noexcept + { + for (size_t i = 0; i < count; i++) { + AppEnvironmentVariable const& env_var = entries[i]; + const char *var_name = &contents[env_var.name_index]; + const char *var_value = &contents[env_var.value_index]; + + setter (var_name, var_value); + } + } + }; +} diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index 7c774584a2e..c2140e2c882 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -339,7 +339,8 @@ extern "C" { [[gnu::visibility("default")]] extern const ApplicationConfig application_config; [[gnu::visibility("default")]] extern const AppEnvironmentVariable app_environment_variables[]; [[gnu::visibility("default")]] extern const char app_environment_variable_contents[]; - [[gnu::visibility("default")]] extern const char* const app_system_properties[]; + [[gnu::visibility("default")]] extern const AppEnvironmentVariable app_system_properties[]; + [[gnu::visibility("default")]] extern const char app_system_property_contents[]; [[gnu::visibility("default")]] extern const char* const mono_aot_mode_name; diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index 4ce0fab92c7..d63f21392e5 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -224,32 +225,34 @@ AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks void AndroidSystem::setup_environment () noexcept { - const char *var_name; - const char *var_value; - for (size_t i = 0uz; i < application_config.environment_variable_count; i++) { - AppEnvironmentVariable const& env_var = app_environment_variables [i]; - var_name = &app_environment_variable_contents[env_var.name_index]; - var_value = &app_environment_variable_contents[env_var.value_index]; - - if constexpr (Constants::is_debug_build) { - log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); - } + if (application_config.environment_variable_count > 0) { + log_debug (LOG_DEFAULT, "Setting environment variables ({})", application_config.environment_variable_count); + HostEnvironment::set_values ( + application_config.environment_variable_count, + app_environment_variables, + app_environment_variable_contents + ); + } - if (setenv (var_name, var_value, 1) < 0) { - log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); - } + if (application_config.system_property_count > 0) { + log_debug (LOG_DEFAULT, "Setting system properties ({})", application_config.system_property_count); + HostEnvironment::set_values ( + application_config.system_property_count, + app_system_properties, + app_system_property_contents + ); } #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); - } + 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 } @@ -289,27 +292,13 @@ AndroidSystem::lookup_system_property (std::string_view const& name, size_t &val 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; + return HostEnvironment::lookup_system_property ( + name, + value_len, + application_config.system_property_count, + app_system_properties, + app_system_property_contents + ); } auto AndroidSystem::get_full_dso_path (std::string const& base_dir, std::string_view const& dso_path, dynamic_local_string& path) noexcept -> bool diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index cbc59d8a99f..14f33be4c29 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -76,7 +76,8 @@ const ApplicationConfig application_config = { // TODO: migrate to std::string_view for these two const AppEnvironmentVariable app_environment_variables[] = {}; const char app_environment_variable_contents[] = {}; -const char* const app_system_properties[] = {}; +const AppEnvironmentVariable app_system_properties[] = {}; +const char app_system_property_contents[] = {}; @@ -138,6 +139,7 @@ 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, + .is_jni_library = true, .name_index = 3, .handle = nullptr, }, @@ -146,6 +148,7 @@ DSOCacheEntry aot_dso_cache[] = { .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, + .is_jni_library = false, .name_index = 4, .handle = nullptr, }, diff --git a/src/native/nativeaot/host/host-environment.cc b/src/native/nativeaot/host/host-environment.cc index 8f647511e66..d1a093f6521 100644 --- a/src/native/nativeaot/host/host-environment.cc +++ b/src/native/nativeaot/host/host-environment.cc @@ -1,15 +1,10 @@ #include -#include +#include #include using namespace xamarin::android; -struct AppEnvironmentVariable { - uint32_t name_index; - uint32_t value_index; -}; - extern "C" { extern const uint32_t __naot_android_app_environment_variable_count; extern const AppEnvironmentVariable __naot_android_app_environment_variables[]; @@ -18,16 +13,23 @@ extern "C" { void HostEnvironment::init () noexcept { - if (__naot_android_app_environment_variable_count == 0) { - return; + if (__naot_android_app_environment_variable_count > 0) { + log_debug (LOG_DEFAULT, "Setting environment variables ({})", __naot_android_app_environment_variable_count); + set_values ( + __naot_android_app_environment_variable_count, + __naot_android_app_environment_variables, + __naot_android_app_environment_variable_contents + ); } - log_debug (LOG_DEFAULT, "Setting {} environment variables", __naot_android_app_environment_variable_count); - for (size_t i = 0; i < __naot_android_app_environment_variable_count; i++) { - AppEnvironmentVariable const& env_var = __naot_android_app_environment_variables[i]; - const char *var_name = &__naot_android_app_environment_variable_contents[env_var.name_index]; - const char *var_value = &__naot_android_app_environment_variable_contents[env_var.value_index]; - - set_variable (var_name, var_value); + if (__naot_android_app_system_property_count == 0) { + return; } + + log_debug (LOG_DEFAULT, "Setting system properties ({})", __naot_android_app_system_property_count); + set_values ( + __naot_android_app_system_property_count, + __naot_android_app_system_properties, + __naot_android_app_system_property_contents + ); } diff --git a/src/native/nativeaot/host/host.cc b/src/native/nativeaot/host/host.cc index ae93cb4ad79..0562d4de408 100644 --- a/src/native/nativeaot/host/host.cc +++ b/src/native/nativeaot/host/host.cc @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/src/native/nativeaot/include/host/host-environment-naot.hh b/src/native/nativeaot/include/host/host-environment-naot.hh new file mode 100644 index 00000000000..9ca099ed101 --- /dev/null +++ b/src/native/nativeaot/include/host/host-environment-naot.hh @@ -0,0 +1,17 @@ +#pragma once + +#include + +// Must be declared before including host-environment.hh +struct AppEnvironmentVariable { + uint32_t name_index; + uint32_t value_index; +}; + +#include + +extern "C" { + extern const uint32_t __naot_android_app_system_property_count; + extern const AppEnvironmentVariable __naot_android_app_system_properties[]; + extern const char __naot_android_app_system_property_contents[]; +} diff --git a/src/native/nativeaot/include/host/host-environment-variables.hh b/src/native/nativeaot/include/host/host-environment-variables.hh new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/native/nativeaot/include/host/host-environment.hh b/src/native/nativeaot/include/host/host-environment.hh deleted file mode 100644 index ceb7ee52f5f..00000000000 --- a/src/native/nativeaot/include/host/host-environment.hh +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -namespace xamarin::android { - class HostEnvironment - { - public: - static void init () noexcept; - - static void set_variable (const char *name, const char *value) noexcept - { - log_debug (LOG_DEFAULT, " Variable {} = '{}'", name, value); - if (::setenv (name, value, 1) < 0) { - log_warn (LOG_DEFAULT, "Failed to set environment variable '{}': {}", name, ::strerror (errno)); - } - } - - static void set_variable (std::string_view const& name, std::string_view const& value) noexcept - { - set_variable (name.data (), value.data ()); - } - }; -} diff --git a/src/native/nativeaot/runtime-base/android-system.cc b/src/native/nativeaot/runtime-base/android-system.cc index 66ce40f344b..52e19c153bc 100644 --- a/src/native/nativeaot/runtime-base/android-system.cc +++ b/src/native/nativeaot/runtime-base/android-system.cc @@ -1,11 +1,18 @@ +#include #include +#include #include using namespace xamarin::android; -auto -AndroidSystem::lookup_system_property ([[maybe_unused]] std::string_view const& name, [[maybe_unused]] size_t &value_len) noexcept -> const char* +auto AndroidSystem::lookup_system_property (std::string_view const& name, size_t &value_len) noexcept -> const char* { - return nullptr; // No-op in NativeAOT + return HostEnvironment::lookup_system_property ( + name, + value_len, + __naot_android_app_system_property_count, + __naot_android_app_system_properties, + __naot_android_app_system_property_contents + ); }