Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b0db8ee
NativeAOT runtime skeleton
grendello Sep 1, 2025
4e110bf
Slowly figuring out NativeAOT build complexities
grendello Sep 1, 2025
f820e54
Link libc++ statically, include Android naot runtime in linking
grendello Sep 2, 2025
b2f02ca
Don't link static libc++, it causes duplicate symbol errors with libs…
grendello Sep 2, 2025
d99bc2d
Add logging to the naot android runtime
grendello Sep 2, 2025
b421b41
Typo
grendello Sep 2, 2025
30f163c
Shared code (gc bridge, os bridge), p/invokes
grendello Sep 3, 2025
1608465
Host code sharing tweaks
grendello Sep 3, 2025
45cef3e
Hook up NAOT-specific GC bridge code
grendello Sep 4, 2025
d0fd36a
Enable ManagedTypeManager
grendello Sep 4, 2025
2a2b188
Bring in the rest of relevant changes from #10402
grendello Sep 4, 2025
82070d5
Temporarily add this, to be removed before merging
grendello Sep 4, 2025
b2df784
Support logger configuration via the standard XA properties
grendello Sep 5, 2025
fe6b999
Beginnings of support for calling custom JNI_OnLoad functions
grendello Sep 5, 2025
6b231c3
Assembly source generation
grendello Sep 8, 2025
d6c907f
JNI on-load initialization of libraries
grendello Sep 9, 2025
29fddc3
Support for environment variables, TBC
grendello Sep 9, 2025
16f2740
[WIP] environment variables + system properties support
grendello Sep 10, 2025
0903848
Environment variables support complete
grendello Sep 10, 2025
2b650c8
Address feedback
grendello Sep 11, 2025
5a11cd4
Remove log spam
grendello Sep 11, 2025
fa18b45
Initialize max gref count
grendello Sep 11, 2025
20a750b
[WIP] System properties
grendello Sep 11, 2025
92f7b20
Partial support for system properties
grendello Sep 12, 2025
c225cfe
Fix after rebase
grendello Sep 15, 2025
73e9449
Post-rebase fixes
grendello Sep 15, 2025
98f62f7
System properties work now
grendello Sep 15, 2025
85ad57d
Share env & sys prop code with CoreCLR
grendello Sep 16, 2025
6981ffb
Statically link libc++, shrink apk by around 8mb
grendello Sep 17, 2025
a0c442f
not needed
grendello Sep 17, 2025
112e0a8
Fixlet
grendello Sep 17, 2025
ebf7df6
Share environment setup code between CoreCLR and NativeAOT
grendello Sep 18, 2025
d93af90
Fix after rebase
grendello Sep 18, 2025
2705848
Post-rebase fixups
grendello Sep 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ static void JNI_OnUnload (IntPtr vm, IntPtr reserved)
}

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

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

// Entry point into Mono.Android.dll
JNIEnvInit.InitializeJniRuntime (runtime);
XA_Host_NativeAOT_OnInit ();
XA_Host_NativeAOT_OnInit (language, filesDir, cacheDir);

transition = new JniTransition (jnienv);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ public class JavaInteropRuntime {
private JavaInteropRuntime() {
}

public static native void init(ClassLoader classLoader);
public static native void init(ClassLoader classLoader, String language, String filesDir, String cacheDir);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.dot.jni.nativeaot;

import java.util.Locale;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
Expand Down Expand Up @@ -27,20 +28,14 @@ public void attachInfo(android.content.Context context, android.content.pm.Provi
ApplicationRegistration.Context = context;
}

// Set environment variables
try {
String filesDir = context.getFilesDir().getAbsolutePath();
String cacheDir = context.getCacheDir().getAbsolutePath();
Os.setenv("HOME", filesDir, true);
Os.setenv("TMPDIR", cacheDir, true);
} catch (ErrnoException e) {
Log.e(TAG, "Failed to set environment variables", e);
}

ClassLoader loader = context.getClassLoader ();
ClassLoader loader = context.getClassLoader ();
Locale locale = Locale.getDefault ();
String language = locale.getLanguage () + "-" + locale.getCountry ();
String filesDir = context.getFilesDir().getAbsolutePath();
String cacheDir = context.getCacheDir().getAbsolutePath();

// Initialize .NET runtime
JavaInteropRuntime.init(loader);
JavaInteropRuntime.init(loader, language, filesDir, cacheDir);
// NOTE: only required for custom applications
ApplicationRegistration.registerApplications();
super.attachInfo (context, info);
Expand Down Expand Up @@ -70,4 +65,4 @@ public int delete(android.net.Uri uri, String where, String[] whereArgs) {
public int update(android.net.Uri uri, android.content.ContentValues values, String where, String[] whereArgs) {
throw new RuntimeException ("This operation is not supported.");
}
}
}
47 changes: 9 additions & 38 deletions src/native/clr/host/host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <host/gc-bridge.hh>
#include <host/fastdev-assemblies.hh>
#include <host/host.hh>
#include <host/host-environment-clr.hh>
#include <host/host-jni.hh>
#include <host/host-util.hh>
#include <host/os-bridge.hh>
Expand Down Expand Up @@ -285,35 +286,6 @@ void Host::gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks,
}
}

void Host::create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept
{
static_local_string<SENSIBLE_PATH_MAX> dir (home_len + relative_path.length ());
Util::path_combine (dir, home.get_string_view (), relative_path);

log_debug (LOG_DEFAULT, "Creating XDG directory: {}"sv, optional_string (dir.get ()));
int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE);
if (rv < 0 && errno != EEXIST) {
log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}"sv, optional_string (dir.get ()), strerror (errno));
}

if (!environment_variable_name.empty ()) {
setenv (environment_variable_name.data (), dir.get (), 1);
}
}

void Host::create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept
{
size_t home_len = strlen (homeDir.get_cstr ());

constexpr auto XDG_DATA_HOME = "XDG_DATA_HOME"sv;
constexpr auto HOME_PATH = ".local/share"sv;
create_xdg_directory (homeDir, home_len, HOME_PATH, XDG_DATA_HOME);

constexpr auto XDG_CONFIG_HOME = "XDG_CONFIG_HOME"sv;
constexpr auto CONFIG_PATH = ".config"sv;
create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME);
}

[[gnu::always_inline]]
auto Host::create_delegate (
std::string_view const& assembly_name, std::string_view const& type_name,
Expand Down Expand Up @@ -434,20 +406,19 @@ void Host::Java_mono_android_Runtime_initInternal (
}

jstring_array_wrapper applicationDirs (env, appDirs);

jstring_wrapper jstr (env, lang);
Util::set_environment_variable ("LANG"sv, jstr);

jstring_wrapper &home = applicationDirs[Constants::APP_DIRS_FILES_DIR_INDEX];
Util::set_environment_variable_for_directory ("TMPDIR"sv, applicationDirs[Constants::APP_DIRS_CACHE_DIR_INDEX]);
Util::set_environment_variable_for_directory ("HOME"sv, home);
create_xdg_directories_and_environment (home);
jstring_wrapper language (env, lang);
jstring_wrapper &files_dir = applicationDirs[Constants::APP_DIRS_FILES_DIR_INDEX];
HostEnvironment::setup_environment (
language,
files_dir,
applicationDirs[Constants::APP_DIRS_CACHE_DIR_INDEX]
);

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

AndroidSystem::detect_embedded_dso_mode (applicationDirs);
AndroidSystem::set_running_in_emulator (isEmulator);
AndroidSystem::set_primary_override_dir (home);
AndroidSystem::set_primary_override_dir (files_dir);
AndroidSystem::create_update_dir (AndroidSystem::get_primary_override_dir ());
AndroidSystem::setup_environment ();

Expand Down
60 changes: 55 additions & 5 deletions src/native/clr/include/host/host-environment.hh
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#pragma once

#include <jni.h>

#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <string_view>

#include <runtime-base/jni-wrappers.hh>
#include <runtime-base/logger.hh>
#include <runtime-base/strings.hh>
#include <runtime-base/util.hh>

struct AppEnvironmentVariable;

Expand All @@ -18,16 +23,19 @@ namespace xamarin::android {
[[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));
}
Util::set_environment_variable (name, value);
}

[[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 ());
Util::set_environment_variable (name.data (), value.data ());
}

[[gnu::flatten, gnu::always_inline]]
static void set_variable (std::string_view const& name, jstring_wrapper &value) noexcept
{
Util::set_environment_variable (name.data (), value);
}

[[gnu::flatten, gnu::always_inline]]
Expand Down Expand Up @@ -72,5 +80,47 @@ namespace xamarin::android {
setter (var_name, var_value);
}
}

private:
[[gnu::flatten, gnu::always_inline]]
static void create_xdg_directory (jstring_wrapper &home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept
{
static_local_string<SENSIBLE_PATH_MAX> dir (home_len + relative_path.length ());
Util::path_combine (dir, home.get_string_view (), relative_path);

log_debug (LOG_DEFAULT, "Creating XDG directory: {}"sv, optional_string (dir.get ()));
int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE);
if (rv < 0 && errno != EEXIST) {
log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}"sv, optional_string (dir.get ()), strerror (errno));
}

if (!environment_variable_name.empty ()) {
set_variable (environment_variable_name.data (), dir.get ());
}
}

[[gnu::flatten, gnu::always_inline]]
static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept
{
size_t home_len = strlen (homeDir.get_cstr ());

constexpr auto XDG_DATA_HOME = "XDG_DATA_HOME"sv;
constexpr auto HOME_PATH = ".local/share"sv;
create_xdg_directory (homeDir, home_len, HOME_PATH, XDG_DATA_HOME);

constexpr auto XDG_CONFIG_HOME = "XDG_CONFIG_HOME"sv;
constexpr auto CONFIG_PATH = ".config"sv;
create_xdg_directory (homeDir, home_len, CONFIG_PATH, XDG_CONFIG_HOME);
}

public:
[[gnu::flatten, gnu::always_inline]]
static void setup_environment (jstring_wrapper &language, jstring_wrapper &files_dir, jstring_wrapper &cache_dir) noexcept
{
set_variable ("LANG"sv, language);
Util::set_environment_variable_for_directory ("TMPDIR"sv, cache_dir);
Util::set_environment_variable_for_directory ("HOME"sv, files_dir);
create_xdg_directories_and_environment (files_dir);
}
};
}
2 changes: 0 additions & 2 deletions src/native/clr/include/host/host.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ namespace xamarin::android {
}

private:
static void create_xdg_directory (jstring_wrapper& home, size_t home_len, std::string_view const& relative_path, std::string_view const& environment_variable_name) noexcept;
static void create_xdg_directories_and_environment (jstring_wrapper &homeDir) noexcept;
static auto zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string<SENSIBLE_PATH_MAX> const& entry_name, uint32_t offset, uint32_t size) -> bool;
static void gather_assemblies_and_libraries (jstring_array_wrapper& runtimeApks, bool have_split_apks);
static void scan_filesystem_for_assemblies_and_libraries () noexcept;
Expand Down
20 changes: 19 additions & 1 deletion src/native/clr/include/runtime-base/util.hh
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,28 @@ namespace xamarin::android {
return get_file_size_at (dirfd, file_name.data ());
}

[[gnu::flatten, gnu::always_inline]]
static void set_environment_variable (const char *name, const char *value) noexcept
{
log_debug (LOG_DEFAULT, "Setting environment 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_environment_variable (std::string_view const& name, jstring_wrapper& value) noexcept
{
::setenv (name.data (), value.get_cstr (), 1);
set_environment_variable (name.data (), value.get_cstr ());
}

[[gnu::flatten, gnu::always_inline]]
static void set_environment_variable (std::string_view const& name, std::string_view const& value) noexcept
{
set_environment_variable (name.data (), value.data ());
}

[[gnu::flatten, gnu::always_inline]]
static void set_environment_variable_for_directory (std::string_view const& name, jstring_wrapper& value, bool createDirectory, mode_t mode) noexcept
{
if (createDirectory) {
Expand All @@ -167,6 +184,7 @@ namespace xamarin::android {
set_environment_variable (name, value);
}

[[gnu::flatten, gnu::always_inline]]
static void set_environment_variable_for_directory (std::string_view const& name, jstring_wrapper &value) noexcept
{
set_environment_variable_for_directory (name, value, true, Constants::DEFAULT_DIRECTORY_MODE);
Expand Down
2 changes: 0 additions & 2 deletions src/native/nativeaot/host/host-environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extern "C" {
void HostEnvironment::init () noexcept
{
if (__naot_android_app_environment_variable_count > 0) {
log_debug (LOG_DEFAULT, "Setting environment variables ({})", __naot_android_app_environment_variable_count);
set_values<set_variable> (
__naot_android_app_environment_variable_count,
__naot_android_app_environment_variables,
Expand All @@ -26,7 +25,6 @@ void HostEnvironment::init () noexcept
return;
}

log_debug (LOG_DEFAULT, "Setting system properties ({})", __naot_android_app_system_property_count);
set_values<set_system_property> (
__naot_android_app_system_property_count,
__naot_android_app_system_properties,
Expand Down
6 changes: 4 additions & 2 deletions src/native/nativeaot/host/host-jni.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <jni.h>

#include <host/host-jni.hh>
#include <host/host-nativeaot.hh>
#include <runtime-base/logger.hh>
Expand All @@ -9,7 +11,7 @@ auto XA_Host_NativeAOT_JNI_OnLoad (JavaVM *vm, void *reserved) -> int
return Host::Java_JNI_OnLoad (vm, reserved);
}

void XA_Host_NativeAOT_OnInit ()
void XA_Host_NativeAOT_OnInit (jstring language, jstring filesDir, jstring cacheDir)
{
Host::OnInit ();
Host::OnInit (language, filesDir, cacheDir);
}
8 changes: 7 additions & 1 deletion src/native/nativeaot/host/host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,16 @@ auto HostCommon::Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint
return JNI_VERSION_1_6;
}

void Host::OnInit () noexcept
void Host::OnInit (jstring language, jstring filesDir, jstring cacheDir) noexcept
{
JNIEnv *env = OSBridge::ensure_jnienv ();
jclass runtimeClass = env->FindClass ("mono/android/Runtime");

jstring_wrapper language_js (env, language);
jstring_wrapper files_dir (env, filesDir);
jstring_wrapper cache_dir (env, cacheDir);
HostEnvironment::setup_environment (language_js, files_dir, cache_dir);

OSBridge::initialize_on_runtime_init (env, runtimeClass);
GCBridge::initialize_on_runtime_init (env, runtimeClass);
BridgeProcessing::naot_initialize_on_runtime_init (env);
Expand Down
2 changes: 1 addition & 1 deletion src/native/nativeaot/include/host/host-jni.hh
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
extern "C" {
[[gnu::visibility("default")]]
auto XA_Host_NativeAOT_JNI_OnLoad (JavaVM *vm, void *reserved) -> int;
void XA_Host_NativeAOT_OnInit ();
void XA_Host_NativeAOT_OnInit (jstring language, jstring filesDir, jstring cacheDir);
}
4 changes: 3 additions & 1 deletion src/native/nativeaot/include/host/host-nativeaot.hh
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#pragma once

#include <jni.h>

#include <host/host-common.hh>

namespace xamarin::android {
class Host : public HostCommon
{
public:
static void OnInit () noexcept;
static void OnInit (jstring language, jstring filesDir, jstring cacheDir) noexcept;
};
}
Loading