Skip to content

Instantly share code, notes, and snippets.

@mdh1418
Created April 3, 2023 21:52
Show Gist options
  • Save mdh1418/941d79c155203fdd9b1b7447bac091a2 to your computer and use it in GitHub Desktop.
Save mdh1418/941d79c155203fdd9b1b7447bac091a2 to your computer and use it in GitHub Desktop.
commit f7a541e3301fff5c08e281fea2345dfe5abe6fa0
Author: mdh1418 <mitchhwang1418@gmail.com>
Date: Fri Mar 31 16:40:49 2023 -0400
Setup end-to-end test on Android
diff --git a/src/mono/msbuild/android/build/AndroidBuild.targets b/src/mono/msbuild/android/build/AndroidBuild.targets
index 26cc272768a..54d2ab13edc 100644
--- a/src/mono/msbuild/android/build/AndroidBuild.targets
+++ b/src/mono/msbuild/android/build/AndroidBuild.targets
@@ -3,7 +3,7 @@
<AndroidGenerateAppBundle Condition="'$(AndroidGenerateAppBundle)' == '' and '$(GenerateAppBundle)' != ''">$(GenerateAppBundle)</AndroidGenerateAppBundle>
<AndroidGenerateAppBundle Condition="'$(AndroidGenerateAppBundle)' == ''">true</AndroidGenerateAppBundle>
<!-- Unable to properly integrate nativelib into app build, so not supported for now. -->
- <AndroidGenerateAppBundle Condition="'$(_IsLibraryMode)' == 'true'">false</AndroidGenerateAppBundle>
+ <AndroidGenerateAppBundle Condition="'$(_IsLibraryMode)' == 'true' and '$(AndroidGenerateAppBundle)' == ''">false</AndroidGenerateAppBundle>
<EnableDefaultAssembliesToBundle Condition="'$(EnableDefaultAssembliesToBundle)' == ''">false</EnableDefaultAssembliesToBundle>
</PropertyGroup>
diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs
index 650281be454..be051b4859c 100644
--- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs
+++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs
@@ -334,7 +334,7 @@ public ApkBuilder(TaskLoggingHelper logger)
nativeLibraries += assemblerFilesToLink.ToString();
string aotSources = assemblerFiles.ToString();
- string monodroidSource = (IsLibraryMode) ? "monodroid-librarymode.c" : "monodroid.c";
+ string monodroidSource = "monodroid.c";//(IsLibraryMode) ? "monodroid-librarymode.c" : "monodroid.c";
string cmakeLists = Utils.GetEmbeddedResource("CMakeLists-android.txt")
.Replace("%ProjectName%", ProjectName)
diff --git a/src/tasks/AndroidAppBuilder/Templates/MainActivity.java b/src/tasks/AndroidAppBuilder/Templates/MainActivity.java
index 360fda7973b..1551c2b3598 100644
--- a/src/tasks/AndroidAppBuilder/Templates/MainActivity.java
+++ b/src/tasks/AndroidAppBuilder/Templates/MainActivity.java
@@ -45,8 +45,11 @@ public class MainActivity extends Activity
@Override
public void run() {
int retcode = MonoRunner.initialize(entryPointLibName, new String[0], ctx);
+ retcode = mdh();
textView.setText("Mono Runtime returned: " + retcode);
}
}, 1000);
}
+
+ public native int mdh();
}
diff --git a/src/tasks/AndroidAppBuilder/Templates/monodroid.c b/src/tasks/AndroidAppBuilder/Templates/monodroid.c
index a016353a0b4..273ca36314b 100644
--- a/src/tasks/AndroidAppBuilder/Templates/monodroid.c
+++ b/src/tasks/AndroidAppBuilder/Templates/monodroid.c
@@ -26,182 +26,6 @@
static char *bundle_path;
static char *executable;
-#define LOG_INFO(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "DOTNET", fmt, ##__VA_ARGS__)
-#define LOG_ERROR(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "DOTNET", fmt, ##__VA_ARGS__)
-
-#if defined(__arm__)
-#define ANDROID_RUNTIME_IDENTIFIER "android-arm"
-#elif defined(__aarch64__)
-#define ANDROID_RUNTIME_IDENTIFIER "android-arm64"
-#elif defined(__i386__)
-#define ANDROID_RUNTIME_IDENTIFIER "android-x86"
-#elif defined(__x86_64__)
-#define ANDROID_RUNTIME_IDENTIFIER "android-x64"
-#else
-#error Unknown architecture
-#endif
-
-#define RUNTIMECONFIG_BIN_FILE "runtimeconfig.bin"
-
-static MonoAssembly*
-mono_droid_load_assembly (const char *name, const char *culture)
-{
- char filename [1024];
- char path [1024];
- int res;
-
- LOG_INFO ("assembly_preload_hook: %s %s %s\n", name, culture, bundle_path);
-
- int len = strlen (name);
- int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3)));
-
- // add extensions if required.
- strlcpy (filename, name, sizeof (filename));
- if (!has_extension) {
- strlcat (filename, ".dll", sizeof (filename));
- }
-
- if (culture && strcmp (culture, ""))
- res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle_path, culture, filename);
- else
- res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle_path, filename);
- assert (res > 0);
-
- struct stat buffer;
- if (stat (path, &buffer) == 0) {
- MonoAssembly *assembly = mono_assembly_open (path, NULL);
- assert (assembly);
- return assembly;
- }
- return NULL;
-}
-
-static MonoAssembly*
-mono_droid_assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data)
-{
- const char *name = mono_assembly_name_get_name (aname);
- const char *culture = mono_assembly_name_get_culture (aname);
- return mono_droid_load_assembly (name, culture);
-}
-
-static unsigned char *
-load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle)
-{
- *out_handle = NULL;
-
- char path [1024];
- int res;
-
- MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly);
- const char *aname = mono_assembly_name_get_name (assembly_name);
-
- LOG_INFO ("Looking for aot data for assembly '%s'.", aname);
- res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle_path, aname);
- assert (res > 0);
-
- int fd = open (path, O_RDONLY);
- if (fd < 0) {
- LOG_INFO ("Could not load the aot data for %s from %s: %s\n", aname, path, strerror (errno));
- return NULL;
- }
-
- void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
- if (ptr == MAP_FAILED) {
- LOG_INFO ("Could not map the aot file for %s: %s\n", aname, strerror (errno));
- close (fd);
- return NULL;
- }
-
- close (fd);
- LOG_INFO ("Loaded aot data for %s.\n", aname);
- *out_handle = ptr;
- return (unsigned char *) ptr;
-}
-
-static void
-free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle)
-{
- munmap (handle, size);
-}
-
-char *
-strdup_printf (const char *msg, ...)
-{
- va_list args;
- char *formatted = NULL;
- va_start (args, msg);
- vasprintf (&formatted, msg, args);
- va_end (args);
- return formatted;
-}
-
-static MonoObject *
-mono_droid_fetch_exception_property (MonoObject *obj, const char *name, bool is_virtual)
-{
- MonoMethod *get = NULL;
- MonoMethod *get_virt = NULL;
- MonoObject *exc = NULL;
-
- get = mono_class_get_method_from_name (mono_get_exception_class (), name, 0);
- if (get) {
- if (is_virtual) {
- get_virt = mono_object_get_virtual_method (obj, get);
- if (get_virt)
- get = get_virt;
- }
-
- return (MonoObject *) mono_runtime_invoke (get, obj, NULL, &exc);
- } else {
- printf ("Could not find the property System.Exception.%s", name);
- }
-
- return NULL;
-}
-
-static char *
-mono_droid_fetch_exception_property_string (MonoObject *obj, const char *name, bool is_virtual)
-{
- MonoString *str = (MonoString *) mono_droid_fetch_exception_property (obj, name, is_virtual);
- return str ? mono_string_to_utf8 (str) : NULL;
-}
-
-void
-unhandled_exception_handler (MonoObject *exc, void *user_data)
-{
- MonoClass *type = mono_object_get_class (exc);
- char *type_name = strdup_printf ("%s.%s", mono_class_get_namespace (type), mono_class_get_name (type));
- char *trace = mono_droid_fetch_exception_property_string (exc, "get_StackTrace", true);
- char *message = mono_droid_fetch_exception_property_string (exc, "get_Message", true);
-
- LOG_ERROR("UnhandledException: %s %s %s", type_name, message, trace);
-
- free (trace);
- free (message);
- free (type_name);
- exit (1);
-}
-
-void
-log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data)
-{
- LOG_INFO ("(%s %s) %s", log_domain, log_level, message);
- if (fatal) {
- LOG_ERROR ("Exit code: %d.", 1);
- exit (1);
- }
-}
-
-#if defined(FORCE_AOT) && defined(STATIC_AOT)
-void register_aot_modules (void);
-#endif
-
-void
-cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
-{
- free (args);
- free (user_data);
-}
-
int
mono_droid_runtime_init (const char* executable, int managed_argc, char* managed_argv[], int local_date_time_offset)
{
@@ -220,85 +44,7 @@ mono_droid_runtime_init (const char* executable, int managed_argc, char* managed
setenv ("DOTNET_DiagnosticPorts", DIAGNOSTIC_PORTS, true);
#endif
- bool wait_for_debugger = false;
- chdir (bundle_path);
-
- // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES
-
- const char* appctx_keys[3];
- appctx_keys[0] = "RUNTIME_IDENTIFIER";
- appctx_keys[1] = "APP_CONTEXT_BASE_DIRECTORY";
- appctx_keys[2] = "System.TimeZoneInfo.LocalDateTimeOffset";
-
- const char* appctx_values[3];
- appctx_values[0] = ANDROID_RUNTIME_IDENTIFIER;
- appctx_values[1] = bundle_path;
- char local_date_time_offset_buffer[32];
- snprintf (local_date_time_offset_buffer, sizeof(local_date_time_offset_buffer), "%d", local_date_time_offset);
- appctx_values[2] = strdup (local_date_time_offset_buffer);
-
- char *file_name = RUNTIMECONFIG_BIN_FILE;
- int str_len = strlen (bundle_path) + strlen (file_name) + 1; // +1 is for the "/"
- char *file_path = (char *)malloc (sizeof (char) * (str_len +1)); // +1 is for the terminating null character
- int num_char = snprintf (file_path, (str_len + 1), "%s/%s", bundle_path, file_name);
- struct stat buffer;
-
- LOG_INFO ("file_path: %s\n", file_path);
- assert (num_char > 0 && num_char == str_len);
-
- if (stat (file_path, &buffer) == 0) {
- MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments));
- arg->kind = 0;
- arg->runtimeconfig.name.path = file_path;
- monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, file_path);
- } else {
- free (file_path);
- }
-
- monovm_initialize(3, appctx_keys, appctx_values);
-
- mono_debug_init (MONO_DEBUG_FORMAT_MONO);
- mono_install_assembly_preload_hook (mono_droid_assembly_preload_hook, NULL);
- mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL);
- mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL);
- mono_trace_set_log_handler (log_callback, NULL);
- mono_set_signal_chaining (true);
- mono_set_crash_chaining (true);
-
- if (wait_for_debugger) {
- char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" };
- mono_jit_parse_options (1, options);
- }
-
-#if FORCE_INTERPRETER
- LOG_INFO("Interp Enabled");
- mono_jit_set_aot_mode(MONO_AOT_MODE_INTERP_ONLY);
-#elif FORCE_AOT
- LOG_INFO("AOT Enabled");
-#if STATIC_AOT
- register_aot_modules();
-#endif // STATIC_AOT
-
-#if FULL_AOT
- mono_jit_set_aot_mode(MONO_AOT_MODE_FULL);
-#else
- mono_jit_set_aot_mode(MONO_AOT_MODE_NORMAL);
-#endif // FULL_AOT
-#endif // FORCE_INTERPRETER
-
- MonoDomain *domain = mono_jit_init_version ("dotnet.android", "mobile");
- assert (domain);
-
- MonoAssembly *assembly = mono_droid_load_assembly (executable, NULL);
- assert (assembly);
-
- LOG_INFO ("Executable: %s", executable);
- int res = mono_jit_exec (domain, assembly, managed_argc, managed_argv);
- LOG_INFO ("Exit code: %d.", res);
-
- mono_jit_cleanup (domain);
-
- return res;
+ return 1418;
}
static void
@@ -311,6 +57,11 @@ strncpy_str (JNIEnv *env, char *buff, jstring str, int nbuff)
(*env)->ReleaseStringUTFChars (env, str, copy_buff);
}
+int
+Java_net_dot_MainActivity_mdh (JNIEnv* env, jobject thiz) {
+ return mdh();
+}
+
void
Java_net_dot_MonoRunner_setEnv (JNIEnv* env, jobject thiz, jstring j_key, jstring j_value)
{
@@ -362,11 +113,3 @@ Java_net_dot_MonoRunner_initRuntime (JNIEnv* env, jobject thiz, jstring j_files_
free(managed_argv);
return res;
}
-
-// called from C#
-void
-invoke_external_native_api (void (*callback)(void))
-{
- if (callback)
- callback();
-}
diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Android.Device_Emulator.Aot_Llvm.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Android.Device_Emulator.Aot_Llvm.Test.csproj
index 49ddce32380..24bfbad7d41 100644
--- a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Android.Device_Emulator.Aot_Llvm.Test.csproj
+++ b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Android.Device_Emulator.Aot_Llvm.Test.csproj
@@ -6,9 +6,12 @@
<TestRuntime>true</TestRuntime>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<MainLibraryFileName>Android.Device_Emulator.Aot_Llvm.Test.dll</MainLibraryFileName>
- <ExpectedExitCode>42</ExpectedExitCode>
+ <ExpectedExitCode>1418</ExpectedExitCode>
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
<MonoEnableLLVM>true</MonoEnableLLVM>
+ <NativeLib>shared</NativeLib>
+ <AndroidGenerateAppBundle>true</AndroidGenerateAppBundle>
+ <ForceFullAOT>true</ForceFullAOT>
</PropertyGroup>
<ItemGroup>
diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/ILLink.Descriptors.xml b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/ILLink.Descriptors.xml
index b1259ec37ac..2d249806b9a 100644
--- a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/ILLink.Descriptors.xml
+++ b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/ILLink.Descriptors.xml
@@ -1,7 +1,7 @@
<linker>
<assembly fullname="Android.Device_Emulator.Aot_Llvm.Test">
<type fullname="Program">
- <method name="SayHello" />
+ <method name="mdh" />
</type>
</assembly>
</linker>
\ No newline at end of file
diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Program.cs
index 916d1f1aa03..e583f49528c 100644
--- a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Program.cs
+++ b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_LLVM/Program.cs
@@ -6,15 +6,14 @@
public static class Program
{
- [UnmanagedCallersOnly(EntryPoint = nameof(SayHello))]
- public static void SayHello()
+ [UnmanagedCallersOnly(EntryPoint="mdh")]
+ public static int mdh()
{
- Console.WriteLine("Called from native! Hello!");
+ return 1418;
}
public static int Main()
{
- Console.WriteLine("Hello, Android!"); // logcat
return 42;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment