-
Notifications
You must be signed in to change notification settings - Fork 540
/
Copy pathmonodroid-glue-internal.hh
296 lines (244 loc) · 11.6 KB
/
monodroid-glue-internal.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
// Dear Emacs, this is a -*- C++ -*- header
#ifndef __MONODROID_GLUE_INTERNAL_H
#define __MONODROID_GLUE_INTERNAL_H
#include <string>
#include <string_view>
#include <jni.h>
#include "android-system.hh"
#include "osbridge.hh"
#include "timing.hh"
#include "cpp-util.hh"
#include "performance-methods.hh"
#include "xxhash.hh"
#include "monodroid-dl.hh"
#include <mono/utils/mono-counters.h>
#include <mono/metadata/profiler.h>
// NDEBUG causes robin_map.h not to include <iostream> which, in turn, prevents indirect inclusion of <mutex>. <mutex>
// conflicts with our std::mutex definition in cppcompat.hh
#if !defined (NDEBUG)
#define NDEBUG
#define NDEBUG_UNDEFINE
#endif
// hush some compiler warnings
#if defined (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif // __clang__
#include <tsl/robin_map.h>
#if defined (__clang__)
#pragma clang diagnostic pop
#endif // __clang__
#if defined (NDEBUG_UNDEFINE)
#undef NDEBUG
#undef NDEBUG_UNDEFINE
#endif
//#include <mono/utils/mono-publib.h>
#include <mono/jit/mono-private-unstable.h>
#include <mono/metadata/mono-private-unstable.h>
// See https://github.com/dotnet/runtime/pull/67024
// See https://github.com/xamarin/xamarin-android/issues/6935
extern mono_bool mono_opt_aot_lazy_assembly_load;
namespace xamarin::android::internal
{
// Values must be identical to those in src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs
enum class TraceKind : uint32_t
{
Java = 0x01,
Managed = 0x02,
Native = 0x04,
Signals = 0x08,
};
enum class MethodEvent
{
JitBegin,
JitFailed,
JitDone,
Enter,
};
class MonodroidRuntime
{
using load_assemblies_context_type = MonoAssemblyLoadContextGCHandle;
#if defined (DEBUG)
struct RuntimeOptions {
bool debug = false;
int loglevel = 0;
int64_t timeout_time = 0;
char *host = nullptr;
uint16_t sdb_port = 0;
uint16_t out_port = 0;
bool server = false;
};
#endif
// Keep the enum values in sync with those in src/Mono.Android/AndroidRuntime/BoundExceptionType.cs
enum class BoundExceptionType : uint8_t
{
System = 0x00,
Java = 0x01,
};
// NOTE: Keep this in sync with managed side in src/Mono.Android/Android.Runtime/JNIEnvInit.cs
struct JnienvInitializeArgs {
JavaVM *javaVm;
JNIEnv *env;
jobject grefLoader;
jmethodID Loader_loadClass;
jclass grefClass;
jmethodID Class_forName;
unsigned int logCategories;
int version;
int grefGcThreshold;
jobject grefIGCUserPeer;
int isRunningOnDesktop;
uint8_t brokenExceptionTransitions;
int packageNamingPolicy;
uint8_t boundExceptionType;
int jniAddNativeMethodRegistrationAttributePresent;
bool jniRemappingInUse;
bool marshalMethodsEnabled;
};
using jnienv_initialize_fn = void (*) (JnienvInitializeArgs*);
using jnienv_register_jni_natives_fn = void (*)(const jchar *typeName_ptr, int32_t typeName_len, jclass jniClass, const jchar *methods_ptr, int32_t methods_len);
private:
static constexpr std::string_view base_apk_name { "/base.apk" };
static constexpr size_t SMALL_STRING_PARSE_BUFFER_LEN = 50uz;
static constexpr bool is_running_on_desktop = false;
public:
static constexpr int XA_LOG_COUNTERS = MONO_COUNTER_JIT | MONO_COUNTER_METADATA | MONO_COUNTER_GC | MONO_COUNTER_GENERICS | MONO_COUNTER_INTERP;
public:
void Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, jclass nativeClass, jstring methods);
void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
jstring runtimeNativeLibDir, jobjectArray appDirs, jint localDateTimeOffset,
jobject loader, jobjectArray assembliesJava, jboolean isEmulator,
jboolean haveSplitApks);
jint Java_JNI_OnLoad (JavaVM *vm, void *reserved);
jclass get_java_class_System () const
{
return java_System;
}
jmethodID get_java_class_method_System_identityHashCode () const
{
return java_System_identityHashCode;
}
jclass get_java_class_TimeZone () const
{
return java_TimeZone;
}
void set_monodroid_gdb_wait (bool yes_no)
{
monodroid_gdb_wait = yes_no;
}
void propagate_uncaught_exception (JNIEnv *env, jobject javaThread, jthrowable javaException);
char* get_java_class_name_for_TypeManager (jclass klass);
void log_traces (JNIEnv *env, TraceKind kind, const char *first_line) noexcept;
void dump_method_events ();
private:
static void mono_log_handler (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data);
static void mono_log_standard_streams_handler (const char *str, mono_bool is_stdout);
// A reference to unique_ptr is not the best practice ever, but it's faster this way
void setup_mono_tracing (std::unique_ptr<char[]> const& mono_log_mask, bool have_log_assembly, bool have_log_gc);
void install_logging_handlers ();
unsigned int convert_dl_flags (int flags);
static void cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data);
template<typename TFunc>
static void load_symbol (void *handle, const char *name, TFunc*& fnptr) noexcept
{
char *err = nullptr;
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);
fnptr = nullptr;
return;
}
fnptr = reinterpret_cast<TFunc*>(symptr);
}
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;
void create_xdg_directories_and_environment (jstring_wrapper &homeDir);
void lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info);
void lookup_bridge_info (MonoImage *image, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info);
void load_assembly (MonoDomain *domain, jstring_wrapper &assembly);
void load_assembly (MonoAssemblyLoadContextGCHandle alc_handle, jstring_wrapper &assembly);
void load_assemblies (load_assemblies_context_type ctx, bool preload, jstring_array_wrapper &assemblies);
void set_debug_options ();
void parse_gdb_options ();
void mono_runtime_init (JNIEnv *env, dynamic_local_string<PROPERTY_VALUE_BUFFER_LEN>& runtime_args);
void init_android_runtime (JNIEnv *env, jclass runtimeClass, jobject loader);
void set_environment_variable_for_directory (const char *name, jstring_wrapper &value, bool createDirectory, mode_t mode);
void set_environment_variable_for_directory (const char *name, jstring_wrapper &value)
{
set_environment_variable_for_directory (name, value, true, DEFAULT_DIRECTORY_MODE);
}
void set_environment_variable (const char *name, jstring_wrapper &value)
{
set_environment_variable_for_directory (name, value, false, 0);
}
static void monodroid_unhandled_exception (MonoObject *java_exception);
MonoClass* get_android_runtime_class ();
MonoDomain* create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks, bool is_root_domain, bool have_split_apks);
MonoDomain* create_and_initialize_domain (JNIEnv* env, jclass runtimeClass, jstring_array_wrapper &runtimeApks,
jstring_array_wrapper &assemblies, jobjectArray assembliesBytes, jstring_array_wrapper &assembliesPaths,
jobject loader, bool is_root_domain, bool force_preload_assemblies,
bool have_split_apks);
void gather_bundled_assemblies (jstring_array_wrapper &runtimeApks, size_t *out_user_assemblies_count, bool have_split_apks);
static bool should_register_file (const char *filename);
void set_trace_options ();
void set_profile_options ();
void log_method_event (MonoMethod *method, MethodEvent event);
static void jit_begin (MonoProfiler *prof, MonoMethod *method);
static void jit_failed (MonoProfiler *prof, MonoMethod *method);
static void jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo);
static void thread_start (MonoProfiler *prof, uintptr_t tid);
static void thread_end (MonoProfiler *prof, uintptr_t tid);
static void prof_method_begin_invoke (MonoProfiler *prof, MonoMethod *method) noexcept;
static void prof_method_end_invoke (MonoProfiler *prof, MonoMethod *method) noexcept;
static void prof_method_enter (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context) noexcept;
static void prof_method_leave (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context) noexcept;
static MonoProfilerCallInstrumentationFlags prof_method_filter (MonoProfiler *prof, MonoMethod *method) noexcept;
#if !defined (RELEASE)
static MonoReflectionType* typemap_java_to_managed (MonoString *java_type_name) noexcept;
static const char* typemap_managed_to_java (MonoReflectionType *type, const uint8_t *mvid) noexcept;
#endif // !def RELEASE
static void monodroid_debugger_unhandled_exception (MonoException *ex);
#if defined (RELEASE)
static const char* get_method_name (uint32_t mono_image_index, uint32_t method_token) noexcept;
static const char* get_class_name (uint32_t class_index) noexcept;
template<bool NeedsLocking>
static void get_function_pointer (uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr) noexcept;
static void get_function_pointer_at_startup (uint32_t mono_image_index, uint32_t class_token, uint32_t method_token, void*& target_ptr) noexcept;
static void get_function_pointer_at_runtime (uint32_t mono_image_index, uint32_t class_token, uint32_t method_token, void*& target_ptr) noexcept;
#endif // def RELEASE
#if defined (DEBUG)
void set_debug_env_vars (void);
bool parse_runtime_args (dynamic_local_string<PROPERTY_VALUE_BUFFER_LEN> &runtime_args, RuntimeOptions *options);
int monodroid_debug_connect (int sock, struct sockaddr_in addr);
int monodroid_debug_accept (int sock, struct sockaddr_in addr);
#endif // DEBUG
#if !defined (RELEASE)
static MonoAssembly* open_from_update_dir (MonoAssemblyName *aname, char **assemblies_path, void *user_data);
#endif
private:
MonoMethod *registerType = nullptr;
volatile bool monodroid_gdb_wait = true;
jclass java_System;
jmethodID java_System_identityHashCode;
jmethodID Class_getName;
jclass java_TimeZone;
MonoProfilerHandle profiler_handle;
/*
* If set, monodroid will spin in a loop until the debugger breaks the wait by
* clearing monodroid_gdb_wait.
*/
bool wait_for_gdb;
/* The context (mapping to a Mono AppDomain) that is currently selected as the
* active context from the point of view of Java. We cannot rely on the value
* of `mono_domain_get` for this as it's stored per-thread and we want to be
* able to switch our different contexts from different threads.
*/
int current_context_id = -1;
jnienv_register_jni_natives_fn jnienv_register_jni_natives = nullptr;
MonoAssemblyLoadContextGCHandle default_alc = nullptr;
static MonoCoreRuntimeProperties monovm_core_properties;
MonovmRuntimeConfigArguments runtime_config_args;
std::unique_ptr<method_event_map_t> method_event_map{};
static inline std::unique_ptr<xamarin::android::mutex> method_event_map_write_lock;
};
}
#endif