Skip to content

Commit 7766c24

Browse files
authored
[nativeaot] Add more compatibility with CoreCLR and MonoVM hosts (#10498)
Add more compatibility with the MonoVM and CoreCLR host environments to the NativeAOT host. It is important that the applications created for MonoVM, then potentially migrated to CoreCLR, found themselves running in an environment as closely resembling the one they were developed and tested in. Add the following to the NativeAOT runtime: * Set up environment variables found in both MonoVM and CoreCLR runtimes. * Create XDG directories expected to exist before managed application code is invoked for the first time. Additionally, stop linking shared version of the `libc++` library, instead use the static one. This shrinks the sample package size by ~8mb and is also a requirement for applications that may themselves use `libc++`, since that could cause conflicts with the binaries produced by the NativeAOT compiler.
1 parent ce1717f commit 7766c24

File tree

12 files changed

+110
-70
lines changed

12 files changed

+110
-70
lines changed

src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ static void JNI_OnUnload (IntPtr vm, IntPtr reserved)
4141
}
4242

4343
[DllImport("xa-internal-api")]
44-
static extern void XA_Host_NativeAOT_OnInit ();
44+
static extern void XA_Host_NativeAOT_OnInit (IntPtr language, IntPtr filesDir, IntPtr cacheDir);
4545

4646
// symbol name from `$(IntermediateOutputPath)obj/Release/osx-arm64/h-classes/net_dot_jni_hello_JavaInteropRuntime.h`
4747
[UnmanagedCallersOnly (EntryPoint="Java_net_dot_jni_nativeaot_JavaInteropRuntime_init")]
48-
static void init (IntPtr jnienv, IntPtr klass, IntPtr classLoader)
48+
static void init (IntPtr jnienv, IntPtr klass, IntPtr classLoader, IntPtr language, IntPtr filesDir, IntPtr cacheDir)
4949
{
5050
JniTransition transition = default;
5151
try {
@@ -65,7 +65,7 @@ static void init (IntPtr jnienv, IntPtr klass, IntPtr classLoader)
6565

6666
// Entry point into Mono.Android.dll
6767
JNIEnvInit.InitializeJniRuntime (runtime);
68-
XA_Host_NativeAOT_OnInit ();
68+
XA_Host_NativeAOT_OnInit (language, filesDir, cacheDir);
6969

7070
transition = new JniTransition (jnienv);
7171

src/Xamarin.Android.Build.Tasks/Resources/JavaInteropRuntime.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ public class JavaInteropRuntime {
1111
private JavaInteropRuntime() {
1212
}
1313

14-
public static native void init(ClassLoader classLoader);
14+
public static native void init(ClassLoader classLoader, String language, String filesDir, String cacheDir);
1515
}

src/Xamarin.Android.Build.Tasks/Resources/NativeAotRuntimeProvider.java

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.dot.jni.nativeaot;
22

3+
import java.util.Locale;
34
import android.system.ErrnoException;
45
import android.system.Os;
56
import android.util.Log;
@@ -27,20 +28,14 @@ public void attachInfo(android.content.Context context, android.content.pm.Provi
2728
ApplicationRegistration.Context = context;
2829
}
2930

30-
// Set environment variables
31-
try {
32-
String filesDir = context.getFilesDir().getAbsolutePath();
33-
String cacheDir = context.getCacheDir().getAbsolutePath();
34-
Os.setenv("HOME", filesDir, true);
35-
Os.setenv("TMPDIR", cacheDir, true);
36-
} catch (ErrnoException e) {
37-
Log.e(TAG, "Failed to set environment variables", e);
38-
}
39-
40-
ClassLoader loader = context.getClassLoader ();
31+
ClassLoader loader = context.getClassLoader ();
32+
Locale locale = Locale.getDefault ();
33+
String language = locale.getLanguage () + "-" + locale.getCountry ();
34+
String filesDir = context.getFilesDir().getAbsolutePath();
35+
String cacheDir = context.getCacheDir().getAbsolutePath();
4136

4237
// Initialize .NET runtime
43-
JavaInteropRuntime.init(loader);
38+
JavaInteropRuntime.init(loader, language, filesDir, cacheDir);
4439
// NOTE: only required for custom applications
4540
ApplicationRegistration.registerApplications();
4641
super.attachInfo (context, info);
@@ -70,4 +65,4 @@ public int delete(android.net.Uri uri, String where, String[] whereArgs) {
7065
public int update(android.net.Uri uri, android.content.ContentValues values, String where, String[] whereArgs) {
7166
throw new RuntimeException ("This operation is not supported.");
7267
}
73-
}
68+
}

src/native/clr/host/host.cc

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <host/gc-bridge.hh>
1616
#include <host/fastdev-assemblies.hh>
1717
#include <host/host.hh>
18+
#include <host/host-environment-clr.hh>
1819
#include <host/host-jni.hh>
1920
#include <host/host-util.hh>
2021
#include <host/os-bridge.hh>
@@ -285,35 +286,6 @@ void Host::gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks,
285286
}
286287
}
287288

288-
void Host::create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept
289-
{
290-
static_local_string<SENSIBLE_PATH_MAX> dir (home_len + relative_path.length ());
291-
Util::path_combine (dir, home.get_string_view (), relative_path);
292-
293-
log_debug (LOG_DEFAULT, "Creating XDG directory: {}"sv, optional_string (dir.get ()));
294-
int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE);
295-
if (rv < 0 && errno != EEXIST) {
296-
log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}"sv, optional_string (dir.get ()), strerror (errno));
297-
}
298-
299-
if (!environment_variable_name.empty ()) {
300-
setenv (environment_variable_name.data (), dir.get (), 1);
301-
}
302-
}
303-
304-
void Host::create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept
305-
{
306-
size_t home_len = strlen (homeDir.get_cstr ());
307-
308-
constexpr auto XDG_DATA_HOME = "XDG_DATA_HOME"sv;
309-
constexpr auto HOME_PATH = ".local/share"sv;
310-
create_xdg_directory (homeDir, home_len, HOME_PATH, XDG_DATA_HOME);
311-
312-
constexpr auto XDG_CONFIG_HOME = "XDG_CONFIG_HOME"sv;
313-
constexpr auto CONFIG_PATH = ".config"sv;
314-
create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME);
315-
}
316-
317289
[[gnu::always_inline]]
318290
auto Host::create_delegate (
319291
std::string_view const& assembly_name, std::string_view const& type_name,
@@ -434,20 +406,19 @@ void Host::Java_mono_android_Runtime_initInternal (
434406
}
435407

436408
jstring_array_wrapper applicationDirs (env, appDirs);
437-
438-
jstring_wrapper jstr (env, lang);
439-
Util::set_environment_variable ("LANG"sv, jstr);
440-
441-
jstring_wrapper &home = applicationDirs[Constants::APP_DIRS_FILES_DIR_INDEX];
442-
Util::set_environment_variable_for_directory ("TMPDIR"sv, applicationDirs[Constants::APP_DIRS_CACHE_DIR_INDEX]);
443-
Util::set_environment_variable_for_directory ("HOME"sv, home);
444-
create_xdg_directories_and_environment (home);
409+
jstring_wrapper language (env, lang);
410+
jstring_wrapper &files_dir = applicationDirs[Constants::APP_DIRS_FILES_DIR_INDEX];
411+
HostEnvironment::setup_environment (
412+
language,
413+
files_dir,
414+
applicationDirs[Constants::APP_DIRS_CACHE_DIR_INDEX]
415+
);
445416

446417
java_TimeZone = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_util_TimeZone"sv, true);
447418

448419
AndroidSystem::detect_embedded_dso_mode (applicationDirs);
449420
AndroidSystem::set_running_in_emulator (isEmulator);
450-
AndroidSystem::set_primary_override_dir (home);
421+
AndroidSystem::set_primary_override_dir (files_dir);
451422
AndroidSystem::create_update_dir (AndroidSystem::get_primary_override_dir ());
452423
AndroidSystem::setup_environment ();
453424

src/native/clr/include/host/host-environment.hh

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
#pragma once
22

3+
#include <jni.h>
4+
35
#include <cerrno>
46
#include <cstdlib>
57
#include <cstring>
68
#include <string_view>
79

10+
#include <runtime-base/jni-wrappers.hh>
811
#include <runtime-base/logger.hh>
12+
#include <runtime-base/strings.hh>
13+
#include <runtime-base/util.hh>
914

1015
struct AppEnvironmentVariable;
1116

@@ -18,16 +23,19 @@ namespace xamarin::android {
1823
[[gnu::flatten, gnu::always_inline]]
1924
static void set_variable (const char *name, const char *value) noexcept
2025
{
21-
log_debug (LOG_DEFAULT, " Variable {} = '{}'", optional_string (name), optional_string (value));
22-
if (::setenv (name, value, 1) < 0) {
23-
log_warn (LOG_DEFAULT, "Failed to set environment variable '{}': {}", name, ::strerror (errno));
24-
}
26+
Util::set_environment_variable (name, value);
2527
}
2628

2729
[[gnu::flatten, gnu::always_inline]]
2830
static void set_variable (std::string_view const& name, std::string_view const& value) noexcept
2931
{
30-
set_variable (name.data (), value.data ());
32+
Util::set_environment_variable (name.data (), value.data ());
33+
}
34+
35+
[[gnu::flatten, gnu::always_inline]]
36+
static void set_variable (std::string_view const& name, jstring_wrapper &value) noexcept
37+
{
38+
Util::set_environment_variable (name.data (), value);
3139
}
3240

3341
[[gnu::flatten, gnu::always_inline]]
@@ -72,5 +80,47 @@ namespace xamarin::android {
7280
setter (var_name, var_value);
7381
}
7482
}
83+
84+
private:
85+
[[gnu::flatten, gnu::always_inline]]
86+
static void create_xdg_directory (jstring_wrapper &home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept
87+
{
88+
static_local_string<SENSIBLE_PATH_MAX> dir (home_len + relative_path.length ());
89+
Util::path_combine (dir, home.get_string_view (), relative_path);
90+
91+
log_debug (LOG_DEFAULT, "Creating XDG directory: {}"sv, optional_string (dir.get ()));
92+
int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE);
93+
if (rv < 0 && errno != EEXIST) {
94+
log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}"sv, optional_string (dir.get ()), strerror (errno));
95+
}
96+
97+
if (!environment_variable_name.empty ()) {
98+
set_variable (environment_variable_name.data (), dir.get ());
99+
}
100+
}
101+
102+
[[gnu::flatten, gnu::always_inline]]
103+
static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept
104+
{
105+
size_t home_len = strlen (homeDir.get_cstr ());
106+
107+
constexpr auto XDG_DATA_HOME = "XDG_DATA_HOME"sv;
108+
constexpr auto HOME_PATH = ".local/share"sv;
109+
create_xdg_directory (homeDir, home_len, HOME_PATH, XDG_DATA_HOME);
110+
111+
constexpr auto XDG_CONFIG_HOME = "XDG_CONFIG_HOME"sv;
112+
constexpr auto CONFIG_PATH = ".config"sv;
113+
create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME);
114+
}
115+
116+
public:
117+
[[gnu::flatten, gnu::always_inline]]
118+
static void setup_environment (jstring_wrapper &language, jstring_wrapper &files_dir, jstring_wrapper &cache_dir) noexcept
119+
{
120+
set_variable ("LANG"sv, language);
121+
Util::set_environment_variable_for_directory ("TMPDIR"sv, cache_dir);
122+
Util::set_environment_variable_for_directory ("HOME"sv, files_dir);
123+
create_xdg_directories_and_environment (files_dir);
124+
}
75125
};
76126
}

src/native/clr/include/host/host.hh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ namespace xamarin::android {
3232
}
3333

3434
private:
35-
static void create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept;
36-
static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept;
3735
static auto zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string<SENSIBLE_PATH_MAX> const& entry_name, uint32_t offset, uint32_t size) -> bool;
3836
static void gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks);
3937
static void scan_filesystem_for_assemblies_and_libraries () noexcept;

src/native/clr/include/runtime-base/util.hh

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,28 @@ namespace xamarin::android {
151151
return get_file_size_at (dirfd, file_name.data ());
152152
}
153153

154+
[[gnu::flatten, gnu::always_inline]]
155+
static void set_environment_variable (const char *name, const char *value) noexcept
156+
{
157+
log_debug (LOG_DEFAULT, "Setting environment variable {} = '{}'", optional_string (name), optional_string (value));
158+
if (::setenv (name, value, 1) < 0) {
159+
log_warn (LOG_DEFAULT, "Failed to set environment variable '{}': {}", name, ::strerror (errno));
160+
}
161+
}
162+
163+
[[gnu::flatten, gnu::always_inline]]
154164
static void set_environment_variable (std::string_view const& name, jstring_wrapper& value) noexcept
155165
{
156-
::setenv (name.data (), value.get_cstr (), 1);
166+
set_environment_variable (name.data (), value.get_cstr ());
157167
}
158168

169+
[[gnu::flatten, gnu::always_inline]]
170+
static void set_environment_variable (std::string_view const& name, std::string_view const& value) noexcept
171+
{
172+
set_environment_variable (name.data (), value.data ());
173+
}
174+
175+
[[gnu::flatten, gnu::always_inline]]
159176
static void set_environment_variable_for_directory (std::string_view const& name, jstring_wrapper& value, bool createDirectory, mode_t mode) noexcept
160177
{
161178
if (createDirectory) {
@@ -167,6 +184,7 @@ namespace xamarin::android {
167184
set_environment_variable (name, value);
168185
}
169186

187+
[[gnu::flatten, gnu::always_inline]]
170188
static void set_environment_variable_for_directory (std::string_view const& name, jstring_wrapper &value) noexcept
171189
{
172190
set_environment_variable_for_directory (name, value, true, Constants::DEFAULT_DIRECTORY_MODE);

src/native/nativeaot/host/host-environment.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ extern "C" {
1414
void HostEnvironment::init () noexcept
1515
{
1616
if (__naot_android_app_environment_variable_count > 0) {
17-
log_debug (LOG_DEFAULT, "Setting environment variables ({})", __naot_android_app_environment_variable_count);
1817
set_values<set_variable> (
1918
__naot_android_app_environment_variable_count,
2019
__naot_android_app_environment_variables,
@@ -26,7 +25,6 @@ void HostEnvironment::init () noexcept
2625
return;
2726
}
2827

29-
log_debug (LOG_DEFAULT, "Setting system properties ({})", __naot_android_app_system_property_count);
3028
set_values<set_system_property> (
3129
__naot_android_app_system_property_count,
3230
__naot_android_app_system_properties,

src/native/nativeaot/host/host-jni.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <jni.h>
2+
13
#include <host/host-jni.hh>
24
#include <host/host-nativeaot.hh>
35
#include <runtime-base/logger.hh>
@@ -9,7 +11,7 @@ auto XA_Host_NativeAOT_JNI_OnLoad (JavaVM *vm, void *reserved) -> int
911
return Host::Java_JNI_OnLoad (vm, reserved);
1012
}
1113

12-
void XA_Host_NativeAOT_OnInit ()
14+
void XA_Host_NativeAOT_OnInit (jstring language, jstring filesDir, jstring cacheDir)
1315
{
14-
Host::OnInit ();
16+
Host::OnInit (language, filesDir, cacheDir);
1517
}

src/native/nativeaot/host/host.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,16 @@ auto HostCommon::Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint
4646
return JNI_VERSION_1_6;
4747
}
4848

49-
void Host::OnInit () noexcept
49+
void Host::OnInit (jstring language, jstring filesDir, jstring cacheDir) noexcept
5050
{
5151
JNIEnv *env = OSBridge::ensure_jnienv ();
5252
jclass runtimeClass = env->FindClass ("mono/android/Runtime");
53+
54+
jstring_wrapper language_js (env, language);
55+
jstring_wrapper files_dir (env, filesDir);
56+
jstring_wrapper cache_dir (env, cacheDir);
57+
HostEnvironment::setup_environment (language_js, files_dir, cache_dir);
58+
5359
OSBridge::initialize_on_runtime_init (env, runtimeClass);
5460
GCBridge::initialize_on_runtime_init (env, runtimeClass);
5561
BridgeProcessing::naot_initialize_on_runtime_init (env);

0 commit comments

Comments
 (0)