diff --git a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs index e0ee094978c..fca55eee042 100644 --- a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs +++ b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs @@ -231,7 +231,7 @@ static void GetDisplayDPI (out float x_dpi, out float y_dpi) x_dpi = metrics.Xdpi; y_dpi = metrics.Ydpi; } - + // This is invoked by // System.Core!System.AndroidPlatform.GetDefaultTimeZone () // DO NOT REMOVE @@ -241,16 +241,13 @@ static string GetDefaultTimeZone () try { return Marshal.PtrToStringAnsi (id); } finally { - monodroid_free (id); + JNIEnv.monodroid_free (id); } } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr _monodroid_timezone_get_default_id (); - [DllImport ("__Internal")] - static extern void monodroid_free (IntPtr ptr); - // This is invoked by // mscorlib.dll!System.AndroidPlatform.GetDefaultSyncContext() // DO NOT REMOVE @@ -265,18 +262,18 @@ static SynchronizationContext GetDefaultSyncContext () // These are invoked by // System.dll!System.AndroidPlatform.getifaddrs // DO NOT REMOVE - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_getifaddrs (out IntPtr ifap); static int GetInterfaceAddresses (out IntPtr ifap) { return _monodroid_getifaddrs (out ifap); } - + // These are invoked by // System.dll!System.AndroidPlatform.freeifaddrs // DO NOT REMOVE - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern void _monodroid_freeifaddrs (IntPtr ifap); static void FreeInterfaceAddresses (IntPtr ifap) @@ -284,7 +281,7 @@ static void FreeInterfaceAddresses (IntPtr ifap) _monodroid_freeifaddrs (ifap); } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern void _monodroid_detect_cpu_and_architecture (ref ushort built_for_cpu, ref ushort running_on_cpu, ref byte is64bit); static void DetectCPUAndArchitecture (out ushort builtForCPU, out ushort runningOnCPU, out bool is64bit) diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs index 8683790aff2..f0fc6bd0f22 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs @@ -75,7 +75,7 @@ public AndroidRuntimeOptions (IntPtr jnienv, IntPtr vm, bool allocNewObjectSuppo class AndroidObjectReferenceManager : JniRuntime.JniObjectReferenceManager { - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_gref_get (); public override int GlobalReferenceCount { @@ -305,7 +305,7 @@ internal static bool CallRegisterMethod (JniNativeMethodRegistrationArguments ar { int idx; - if (typeName == null || !typesMap.TryGetValue (typeName, out idx)) + if (typeName == null || !typesMap.TryGetValue (typeName, out idx)) return false; return CallRegisterMethodByIndex (arguments, idx); @@ -344,7 +344,7 @@ public override void RegisterNativeMembers (JniType jniType, Type type, string m throw new InvalidOperationException (String.Format ("Specified managed method '{0}' was not found. Signature: {1}", mname, toks [1])); callback = CreateDynamicCallback (minfo); } else { - GetCallbackHandler connector = (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler), + GetCallbackHandler connector = (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler), toks.Length == 4 ? Type.GetType (toks [3], true) : type, toks [2]); callback = connector (); } diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 6555ed732fe..ee373df9f26 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -23,17 +23,17 @@ struct JnienvInitializeArgs { public IntPtr grefClass; public IntPtr Class_forName; public uint logCategories; - public IntPtr Class_getName; public int version; public int androidSdkVersion; public int localRefsAreIndirect; public int grefGcThreshold; public IntPtr grefIGCUserPeer; public int isRunningOnDesktop; + public byte brokenExceptionTransitions; + public int packageNamingPolicy; } public static partial class JNIEnv { - static IntPtr java_class_loader; static IntPtr java_vm; static IntPtr load_class_id; @@ -46,10 +46,10 @@ public static partial class JNIEnv { static IntPtr cid_System; static IntPtr mid_System_identityHashCode; + static IntPtr grefIGCUserPeer_class; internal static int gref_gc_threshold; - internal static IntPtr mid_Class_getName; - + internal static bool PropagateExceptions; static UncaughtExceptionHandler defaultUncaughtExceptionHandler; @@ -57,56 +57,35 @@ public static partial class JNIEnv { static AndroidRuntime androidRuntime; -#if !JAVA_INTEROP - static JNIInvokeInterface invoke_iface; + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + extern static void monodroid_log (LogLevel level, LogCategories category, string message); - [ThreadStatic] static IntPtr handle; - [ThreadStatic] static JniNativeInterfaceInvoker env; + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + extern static IntPtr monodroid_timing_start (string message); - static JniNativeInterfaceInvoker Env { - get { - if (Handle == IntPtr.Zero) // Forces thread attach if necessary. - throw new Exception ("JNIEnv handle is NULL"); - return env; - } - } + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + extern static void monodroid_timing_stop (IntPtr sequence, string message); - static void SetEnv () - { - int r; - if ((r = invoke_iface.GetEnv (java_vm, out handle, version)) != 0) - AndroidEnvironment.FailFast ("Unable to get JNI Environment pointer! " + - "GetEnv(vm=0x" + java_vm.ToString ("x") + ", version=0x" + version.ToString ("x") + ")=" + r + - "; gettid()=" + gettid () + - "; Thread.ManagedThreadId=" + Thread.CurrentThread.ManagedThreadId + - "; Thread.Name=\"" + Thread.CurrentThread.Name + "\"" + - "; at: " + new StackTrace (true).ToString ()); - env = CreateNativeInterface (); - } -#endif // !JAVA_INTEROP + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + internal extern static void monodroid_free (IntPtr ptr); public static IntPtr Handle { get { -#if JAVA_INTEROP return JniEnvironment.EnvironmentPointer; -#else // !JAVA_INTEROP - if (handle == IntPtr.Zero) { - SetEnv (); - } - return handle; -#endif // !JAVA_INTEROP } } public static void CheckHandle (IntPtr jnienv) { -#if JAVA_INTEROP new JniTransition (jnienv).Dispose (); -#else // !JAVA_INTEROP - if (Handle != jnienv) { - SetEnv (); - } -#endif // !JAVA_INTEROP + } + + internal static bool IsGCUserPeer (IntPtr value) + { + if (value == IntPtr.Zero) + return false; + + return IsInstanceOf (value, grefIGCUserPeer_class); } [DllImport ("libc")] @@ -115,68 +94,37 @@ public static void CheckHandle (IntPtr jnienv) static unsafe void RegisterJniNatives (IntPtr typeName_ptr, int typeName_len, IntPtr jniClass, IntPtr methods_ptr, int methods_len) { string typeName = new string ((char*) typeName_ptr, 0, typeName_len); - - var __start = new DateTime (); - if (Logger.LogTiming) { - __start = DateTime.UtcNow; - Logger.Log (LogLevel.Info, - "monodroid-timing", - "JNIEnv.RegisterJniNatives (\"" + typeName + "\", 0x" + jniClass.ToString ("x") + ") start: " + (__start - new DateTime (1970, 1, 1)).TotalMilliseconds); - } - Type type = Type.GetType (typeName); if (type == null) { - Logger.Log (LogLevel.Error, "MonoDroid", - "Could not load type '" + typeName + "'. Skipping JNI registration of type '" + - Java.Interop.TypeManager.GetClassName (jniClass) + "'."); + monodroid_log (LogLevel.Error, + LogCategories.Default, + $"Could not load type '{typeName}'. Skipping JNI registration of type '{Java.Interop.TypeManager.GetClassName (jniClass)}'."); return; } var className = Java.Interop.TypeManager.GetClassName (jniClass); - TypeManager.RegisterType (className, type); + Java.Interop.TypeManager.RegisterType (className, type); JniType jniType = null; JniType.GetCachedJniType (ref jniType, className); androidRuntime.TypeManager.RegisterNativeMembers (jniType, type, methods_ptr == IntPtr.Zero ? null : new string ((char*) methods_ptr, 0, methods_len)); - - if (Logger.LogTiming) { - var __end = DateTime.UtcNow; - Logger.Log (LogLevel.Info, - "monodroid-timing", - "JNIEnv.RegisterJniNatives total time: " + (__end - new DateTime (1970, 1, 1)).TotalMilliseconds + " [elapsed: " + (__end - __start).TotalMilliseconds + " ms]"); - } } internal static unsafe void Initialize (JnienvInitializeArgs* args) { - Logger.Categories = (LogCategories) args->logCategories; - - Stopwatch stopper = null; - long elapsed, totalElapsed = 0; - if (Logger.LogTiming) { - stopper = new Stopwatch (); - stopper.Start (); - Logger.Log (LogLevel.Info, "monodroid-timing", "JNIEnv.Initialize start"); - elapsed = stopper.ElapsedMilliseconds; - totalElapsed += elapsed; - Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize: Logger JIT/etc. time: elapsed {elapsed} ms]"); - stopper.Restart (); + bool logTiming = (args->logCategories & (uint)LogCategories.Timing) != 0; + IntPtr total_timing_sequence = IntPtr.Zero; + IntPtr partial_timing_sequence = IntPtr.Zero; + if (logTiming) { + total_timing_sequence = monodroid_timing_start ("JNIEnv.Initialize start"); + partial_timing_sequence = monodroid_timing_start (null); } gref_gc_threshold = args->grefGcThreshold; - mid_Class_getName = args->Class_getName; - java_vm = args->javaVm; -#if !JAVA_INTEROP - handle = args->env; - env = CreateNativeInterface (); - - invoke_iface = (JNIInvokeInterface) Marshal.PtrToStructure (Marshal.ReadIntPtr (java_vm), typeof (JNIInvokeInterface)); -#endif // !JAVA_INTEROP - version = args->version; androidSdkVersion = args->androidSdkVersion; @@ -193,60 +141,31 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args) Mono.SystemDependencyProvider.Initialize (); -#if JAVA_INTEROP androidRuntime = new AndroidRuntime (args->env, args->javaVm, androidSdkVersion > 10, args->grefLoader, args->Loader_loadClass); -#endif // JAVA_INTEROP - - if (Logger.LogTiming) { - elapsed = stopper.ElapsedMilliseconds; - totalElapsed += elapsed; - Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize: managed runtime init time: elapsed {elapsed} ms]"); - stopper.Restart (); - var _ = Java.Interop.TypeManager.jniToManaged; - elapsed = stopper.ElapsedMilliseconds; - totalElapsed += elapsed; - Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize: TypeManager init time: elapsed {elapsed} ms]"); - } AllocObjectSupported = androidSdkVersion > 10; - IsRunningOnDesktop = Convert.ToBoolean (args->isRunningOnDesktop); + IsRunningOnDesktop = args->isRunningOnDesktop == 1; - Java.Interop.Runtime.grefIGCUserPeer_class = args->grefIGCUserPeer; + grefIGCUserPeer_class = args->grefIGCUserPeer; + + PropagateExceptions = args->brokenExceptionTransitions == 0; -#if BROKEN_EXCEPTION_TRANSITIONS // XA < 5.0 - var propagate = - Environment.GetEnvironmentVariable ("__XA_PROPAGATE_EXCEPTIONS__") ?? - Environment.GetEnvironmentVariable ("__XA_PROPOGATE_EXCEPTIONS__"); - if (!string.IsNullOrEmpty (propagate)) { - bool.TryParse (propagate, out PropagateExceptions); - } - if (PropagateExceptions) { - Logger.Log (LogLevel.Info, - "monodroid", - "Enabling managed-to-java exception propagation."); - } -#else - PropagateExceptions = true; - var brokenExceptionTransitions = Environment.GetEnvironmentVariable ("XA_BROKEN_EXCEPTION_TRANSITIONS"); - bool brokenTransitions; - if (!string.IsNullOrEmpty (brokenExceptionTransitions) && bool.TryParse (brokenExceptionTransitions, out brokenTransitions)) { - PropagateExceptions = !brokenTransitions; - } -#endif if (PropagateExceptions) { defaultUncaughtExceptionHandler = new UncaughtExceptionHandler (Java.Lang.Thread.DefaultUncaughtExceptionHandler); if (!IsRunningOnDesktop) Java.Lang.Thread.DefaultUncaughtExceptionHandler = defaultUncaughtExceptionHandler; } - var packageNamingPolicy = Environment.GetEnvironmentVariable ("__XA_PACKAGE_NAMING_POLICY__"); - if (Enum.TryParse (packageNamingPolicy, out PackageNamingPolicy pnp)) { - JavaNativeTypeManager.PackageNamingPolicy = pnp; + JavaNativeTypeManager.PackageNamingPolicy = (PackageNamingPolicy)args->packageNamingPolicy; + if (IsRunningOnDesktop) { + string packageNamingPolicy = Environment.GetEnvironmentVariable ("__XA_PACKAGE_NAMING_POLICY__"); + if (Enum.TryParse (packageNamingPolicy, out PackageNamingPolicy pnp)) { + JavaNativeTypeManager.PackageNamingPolicy = pnp; + } } - if (Logger.LogTiming) { - totalElapsed += stopper.ElapsedMilliseconds; - Logger.Log (LogLevel.Info, "monodroid-timing", $"JNIEnv.Initialize end: elapsed {totalElapsed} ms"); + if (logTiming) { + monodroid_timing_stop (total_timing_sequence, "JNIEnv.Initialize end"); } } @@ -259,7 +178,6 @@ internal static void Exit () if (uncaughtExceptionHandler != null && uncaughtExceptionHandler == defaultUncaughtExceptionHandler) Java.Lang.Thread.DefaultUncaughtExceptionHandler = uncaughtExceptionHandler.DefaultHandler; -#if JAVA_INTEROP /* Manually dispose surfaced objects and close the current JniEnvironment to * avoid ObjectDisposedException thrown on finalizer threads after shutdown */ @@ -270,9 +188,7 @@ internal static void Exit () obj.Dispose (); continue; } catch (Exception e) { - Logger.Log (LogLevel.Warn, - "monodroid", - string.Format ("Couldn't dispose object: {0}", e)); + monodroid_log (LogLevel.Warn, LogCategories.Default, $"Couldn't dispose object: {e}"); } /* If calling Dispose failed, the assumption is that user-code in * the Dispose(bool) overload is to blame for it. In that case we @@ -283,7 +199,6 @@ internal static void Exit () ManualJavaObjectDispose (jobj); } JniEnvironment.Runtime.Dispose (); -#endif // JAVA_INTEROP } /* FIXME: This reproduces the minimal steps in Java.Lang.Object.Dispose @@ -312,7 +227,7 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt defaultUncaughtExceptionHandler.UncaughtException (javaThread, javaException); } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] extern static void _monodroid_gc_wait_for_bridge_processing (); static volatile bool BridgeProcessing; // = false @@ -324,7 +239,7 @@ public static void WaitForBridgeProcessing () _monodroid_gc_wait_for_bridge_processing (); } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] extern static IntPtr _monodroid_get_identity_hash_code (IntPtr env, IntPtr value); internal static Func IdentityHash; @@ -487,14 +402,6 @@ public static unsafe IntPtr CreateInstance (Type type, string signature, params return CreateInstance (type, signature, cp); } -#if !JAVA_INTEROP - static unsafe JniNativeInterfaceInvoker CreateNativeInterface () - { - JniNativeInterfaceStruct* p = (JniNativeInterfaceStruct*) Marshal.ReadIntPtr (Handle); - return new JniNativeInterfaceInvoker (p); - } -#endif // !JAVA_INTEROP - public static IntPtr FindClass (System.Type type) { int rank = JavaNativeTypeManager.GetArrayInfo (type, out type); @@ -503,7 +410,7 @@ public static IntPtr FindClass (System.Type type) } catch (Java.Lang.Throwable e) { if (!((e is Java.Lang.NoClassDefFoundError) || (e is Java.Lang.ClassNotFoundException))) throw; - Logger.Log (LogLevel.Warn, "monodroid", "JNIEnv.FindClass(Type) caught unexpected exception: " + e); + monodroid_log (LogLevel.Warn, LogCategories.Default, $"JNIEnv.FindClass(Type) caught unexpected exception: {e}"); string jni = Java.Interop.TypeManager.GetJniTypeName (type); if (jni != null) { e.Dispose (); @@ -583,58 +490,26 @@ public static void Throw (IntPtr obj) { if (obj == IntPtr.Zero) throw new ArgumentException ("'obj' must not be IntPtr.Zero.", "obj"); -#if JAVA_INTEROP + JniEnvironment.Exceptions.Throw (new JniObjectReference (obj)); -#else // !JAVA_INTEROP - if (Env.Throw (Handle, obj) != 0) { - ExceptionDescribe (); - AndroidEnvironment.FailFast ("Unable to raise a Java exception!"); - } -#endif // !JAVA_INTEROP } public static void ThrowNew (IntPtr clazz, string message) { if (message == null) throw new ArgumentNullException ("message"); -#if JAVA_INTEROP + JniEnvironment.Exceptions.ThrowNew (new JniObjectReference (clazz), message); -#else // !JAVA_INTEROP - if (Env.ThrowNew (Handle, clazz, message) != 0) { - ExceptionDescribe (); - AndroidEnvironment.FailFast ("Unable to raise a Java exception!"); - } -#endif // !JAVA_INTEROP } public static void PushLocalFrame (int capacity) { -#if JAVA_INTEROP JniEnvironment.References.PushLocalFrame (capacity); -#else // !JAVA_INTEROP - int rvalue = Env._PushLocalFrame (Handle, capacity); - - if (rvalue != 0) { - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - } -#endif // !JAVA_INTEROP } public static void EnsureLocalCapacity (int capacity) { -#if JAVA_INTEROP JniEnvironment.References.EnsureLocalCapacity (capacity); -#else // !JAVA_INTEROP - int rvalue = Env._EnsureLocalCapacity (Handle, capacity); - - if (rvalue != 0) { - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - } -#endif // !JAVA_INTEROP } internal static void DeleteRef (IntPtr handle, JniHandleOwnership transfer) @@ -651,166 +526,66 @@ internal static void DeleteRef (IntPtr handle, JniHandleOwnership transfer) } } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_gref_log (string message); - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_gref_log_new (IntPtr curHandle, byte curType, IntPtr newHandle, byte newType, string threadName, int threadId, [In] StringBuilder from, int from_writable); - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_gref_log_delete (IntPtr handle, byte type, string threadName, int threadId, [In] StringBuilder from, int from_writable); - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_weak_gref_new (IntPtr curHandle, byte curType, IntPtr newHandle, byte newType, string threadName, int threadId, [In] StringBuilder from, int from_writable); - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_weak_gref_delete (IntPtr handle, byte type, string threadName, int threadId, [In] StringBuilder from, int from_writable); - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_lref_log_new (int lrefc, IntPtr handle, byte type, string threadName, int threadId, [In] StringBuilder from, int from_writable); - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_lref_log_delete (int lrefc, IntPtr handle, byte type, string threadName, int threadId, [In] StringBuilder from, int from_writable); public static IntPtr NewGlobalRef (IntPtr jobject) { -#if JAVA_INTEROP var r = new JniObjectReference (jobject); return r.NewGlobalRef ().Handle; -#else // !JAVA_INTEROP - IntPtr res = Env.NewGlobalRef (Handle, jobject); - var log = Logger.LogGlobalRef; - var ctype = log ? _GetObjectRefType (jobject) : (byte) '*'; - var ntype = log ? _GetObjectRefType (res) : (byte) '*'; - var tname = log ? Thread.CurrentThread.Name : null; - var tid = log ? Thread.CurrentThread.ManagedThreadId : 0; - var from = log ? new StringBuilder (new StackTrace (true).ToString ()) : null; - int gc = _monodroid_gref_log_new (jobject, ctype, res, ntype, tname, tid, from, 1); - if (gc >= gref_gc_threshold) { - Logger.Log (LogLevel.Info, "monodroid-gc", gc + " outstanding GREFs. Performing a full GC!"); - System.GC.Collect (); - } - return res; -#endif // !JAVA_INTEROP } public static void DeleteGlobalRef (IntPtr jobject) { -#if JAVA_INTEROP var r = new JniObjectReference (jobject, JniObjectReferenceType.Global); JniObjectReference.Dispose (ref r); -#else // !JAVA_INTEROP - var log = Logger.LogGlobalRef; - var ctype = log ? _GetObjectRefType (jobject) : (byte) '*'; - var tname = log ? Thread.CurrentThread.Name : null; - var tid = log ? Thread.CurrentThread.ManagedThreadId : 0; - var from = log ? new StringBuilder (new StackTrace (true).ToString ()) : null; - _monodroid_gref_log_delete (jobject, ctype, tname, tid, from, 1); - Env.DeleteGlobalRef (Handle, jobject); -#endif // !JAVA_INTEROP } -#if !JAVA_INTEROP - internal static int lref_count; - - static IntPtr LogCreateLocalRef (IntPtr jobject) - { - if (jobject == IntPtr.Zero) - return jobject; - - if (Logger.LogLocalRef) { - var v = Interlocked.Increment (ref lref_count); - - var tname = Thread.CurrentThread.Name; - var tid = Thread.CurrentThread.ManagedThreadId;; - var from = new StringBuilder (new StackTrace (true).ToString ()); - _monodroid_lref_log_new (v, jobject, (byte) 'L', tname, tid, from, 1); - } - return jobject; - } -#endif // !JAVA_INTEROP - public static IntPtr NewLocalRef (IntPtr jobject) { -#if JAVA_INTEROP return new JniObjectReference (jobject).NewLocalRef ().Handle; -#else // !JAVA_INTEROP - return LogCreateLocalRef (Env.NewLocalRef (Handle, jobject)); -#endif // !JAVA_INTEROP } public static void DeleteLocalRef (IntPtr jobject) { -#if JAVA_INTEROP var r = new JniObjectReference (jobject, JniObjectReferenceType.Local); JniObjectReference.Dispose (ref r); -#else // !JAVA_INTEROP - Env.DeleteLocalRef (Handle, jobject); - - if (jobject == IntPtr.Zero) - return; - - if (Logger.LogLocalRef) { - var v = Interlocked.Decrement (ref lref_count); - - var tname = Thread.CurrentThread.Name; - var tid = Thread.CurrentThread.ManagedThreadId;; - var from = new StringBuilder (new StackTrace (true).ToString ()); - _monodroid_lref_log_delete (v, jobject, (byte) 'L', tname, tid, from, 1); - } -#endif // !JAVA_INTEROP } public static void DeleteWeakGlobalRef (IntPtr jobject) { -#if JAVA_INTEROP var r = new JniObjectReference (jobject, JniObjectReferenceType.WeakGlobal); JniObjectReference.Dispose (ref r); -#else // !JAVA_INTEROP - var log = Logger.LogGlobalRef; - var ctype = log ? _GetObjectRefType (jobject) : (byte) '*'; - var tname = log ? Thread.CurrentThread.Name : null; - var tid = log ? Thread.CurrentThread.ManagedThreadId : 0; - var from = log ? new StringBuilder (new StackTrace (true).ToString ()) : null; - _monodroid_weak_gref_delete (jobject, ctype, tname, tid, from, 1); - Env.DeleteWeakGlobalRef (Handle, jobject); -#endif // !JAVA_INTEROP } public static IntPtr NewObject (IntPtr jclass, IntPtr jmethod) { -#if JAVA_INTEROP var r = JniEnvironment.Object.NewObject (new JniObjectReference (jclass), new JniMethodInfo (jmethod, isStatic: false)); return r.Handle; -#else // !JAVA_INTEROP - Java.Interop.TypeManager.ActivationEnabled = false; - IntPtr rvalue = Env.NewObject (Handle, jclass, jmethod); - Java.Interop.TypeManager.ActivationEnabled = true; - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - - return LogCreateLocalRef (rvalue); -#endif // !JAVA_INTEROP } public static unsafe IntPtr NewObject (IntPtr jclass, IntPtr jmethod, JValue* parms) { -#if JAVA_INTEROP var r = JniEnvironment.Object.NewObject (new JniObjectReference (jclass), new JniMethodInfo (jmethod, isStatic: false), (JniArgumentValue*) parms); return r.Handle; -#else // !JAVA_INTEROP - Java.Interop.TypeManager.ActivationEnabled = false; - IntPtr rvalue = Env.NewObjectA (Handle, jclass, jmethod, parms); - Java.Interop.TypeManager.ActivationEnabled = true; - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - - return LogCreateLocalRef (rvalue); -#endif // !JAVA_INTEROP } public static unsafe IntPtr NewObject (IntPtr jclass, IntPtr jmethod, params JValue[] parms) @@ -829,7 +604,7 @@ public static string GetClassNameFromInstance (IntPtr jobject) } } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr monodroid_typemap_managed_to_java (string managed); public static string GetJniName (Type type) @@ -859,62 +634,25 @@ public static IntPtr ToLocalJniHandle (IJavaObject value) return NewLocalRef (value.Handle); } -#if !JAVA_INTEROP - static JObjectRefType GetObjectRefType (IntPtr jobject) - { - return (JObjectRefType) Env.GetObjectRefType (Handle, jobject); - } - - static byte _GetObjectRefType (IntPtr jobject) - { - var value = GetObjectRefType (jobject); - switch (value) { - case JObjectRefType.Invalid: return (byte) 'I'; - case JObjectRefType.Local: return (byte) 'L'; - case JObjectRefType.Global: return (byte) 'G'; - case JObjectRefType.WeakGlobal: return (byte) 'W'; - default: return (byte) '*'; - } - } -#endif // !JAVA_INTEROP - static IntPtr char_sequence_to_string_id; public static string GetCharSequence (IntPtr jobject, JniHandleOwnership transfer) { if (jobject == IntPtr.Zero) return null; -#if JAVA_INTEROP + var r = JniEnvironment.Object.ToString (new JniObjectReference (jobject)); return JniEnvironment.Strings.ToString (ref r, JniObjectReferenceOptions.CopyAndDispose); -#else // !JAVA_INTEROP - IntPtr str = LogCreateLocalRef (Env.CallObjectMethod (Handle, jobject, Java.Lang.Class.CharSequence_toString)); - try { - return GetString (str, JniHandleOwnership.TransferLocalRef); - } finally { - DeleteRef (jobject, transfer); - } -#endif // !JAVA_INTEROP } public static unsafe string GetString (IntPtr value, JniHandleOwnership transfer) { if (value == IntPtr.Zero) return null; -#if JAVA_INTEROP + var s = JniEnvironment.Strings.ToString (new JniObjectReference (value)); DeleteRef (value, transfer); return s; -#else // !JAVA_INTEROP - int len = Env.GetStringLength (Handle, value); - IntPtr chars = Env.GetStringChars (Handle, value, IntPtr.Zero); - try { - return new string ((char*) chars, 0, len); - } finally { - Env.ReleaseStringChars (Handle, value, chars); - DeleteRef (value, transfer); - } -#endif // !JAVA_INTEROP } public static unsafe IntPtr NewString (string text) @@ -922,19 +660,7 @@ public static unsafe IntPtr NewString (string text) if (text == null) return IntPtr.Zero; -#if JAVA_INTEROP return JniEnvironment.Strings.NewString (text).Handle; -#else // !JAVA_INTEROP - IntPtr rvalue; - fixed (char *s = text) - rvalue = LogCreateLocalRef (Env.NewString (Handle, (IntPtr) s, text.Length)); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - - return rvalue; -#endif // !JAVA_INTEROP } public static unsafe IntPtr NewString (char[] text, int length) @@ -942,20 +668,8 @@ public static unsafe IntPtr NewString (char[] text, int length) if (text == null) return IntPtr.Zero; -#if JAVA_INTEROP fixed (char *s = text) return JniEnvironment.Strings.NewString (s, length).Handle; -#else // !JAVA_INTEROP - IntPtr rvalue; - fixed (char *s = text) - rvalue = LogCreateLocalRef (Env.NewString (Handle, (IntPtr) s, length)); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - - return rvalue; -#endif // !JAVA_INTEROP } static void AssertCompatibleArrayTypes (Type sourceType, IntPtr destArray) @@ -1127,118 +841,50 @@ static TValue GetConverter(Dictionary dict, Type elementTy static unsafe void _GetBooleanArrayRegion (IntPtr array, int start, int length, bool[] buffer) { -#if JAVA_INTEROP fixed (bool* p = buffer) JniEnvironment.Arrays.GetBooleanArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - byte[] b = new byte [buffer.Length]; - Env.GetBooleanArrayRegion (Handle, array, start, length, b); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - - for (int i = 0; i < buffer.Length; ++i) - buffer [i] = b [i] != 0; -#endif // !JAVA_INTEROP } static unsafe void _GetByteArrayRegion (IntPtr array, int start, int length, byte[] buffer) { -#if JAVA_INTEROP fixed (byte* p = buffer) JniEnvironment.Arrays.GetByteArrayRegion (new JniObjectReference (array), start, length, (sbyte*) p); -#else // !JAVA_INTEROP - Env.GetByteArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _GetCharArrayRegion (IntPtr array, int start, int length, char[] buffer) { -#if JAVA_INTEROP fixed (char* p = buffer) JniEnvironment.Arrays.GetCharArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.GetCharArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _GetShortArrayRegion (IntPtr array, int start, int length, short[] buffer) { -#if JAVA_INTEROP fixed (short* p = buffer) JniEnvironment.Arrays.GetShortArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.GetShortArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _GetIntArrayRegion (IntPtr array, int start, int length, int[] buffer) { -#if JAVA_INTEROP fixed (int* p = buffer) JniEnvironment.Arrays.GetIntArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.GetIntArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _GetLongArrayRegion (IntPtr array, int start, int length, long[] buffer) { -#if JAVA_INTEROP fixed (long* p = buffer) JniEnvironment.Arrays.GetLongArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.GetLongArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _GetFloatArrayRegion (IntPtr array, int start, int length, float[] buffer) { -#if JAVA_INTEROP fixed (float* p = buffer) JniEnvironment.Arrays.GetFloatArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.GetFloatArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _GetDoubleArrayRegion (IntPtr array, int start, int length, double[] buffer) { -#if JAVA_INTEROP fixed (double* p = buffer) JniEnvironment.Arrays.GetDoubleArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.GetDoubleArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } public static void CopyArray (IntPtr src, Array dest, Type elementType = null) @@ -1303,15 +949,8 @@ public static unsafe void CopyArray (bool[] src, IntPtr dest) AssertCompatibleArrayTypes (typeof (bool[]), dest); -#if JAVA_INTEROP fixed (bool* p = src) JniEnvironment.Arrays.SetBooleanArrayRegion (new JniObjectReference (dest), 0, src.Length, p); -#else // !JAVA_INTEROP - byte[] bytes = new byte [src.Length]; - for (int i = 0; i < src.Length; i++) - bytes [i] = (byte) (src [i] ? 1 : 0); - SetBooleanArrayRegion (dest, 0, src.Length, bytes); -#endif // !JAVA_INTEROP } public static void CopyArray (string[] src, IntPtr dest) @@ -1321,11 +960,7 @@ public static void CopyArray (string[] src, IntPtr dest) for (int i = 0; i < src.Length; i++) { IntPtr native = NewString (src [i]); -#if JAVA_INTEROP JniEnvironment.Arrays.SetObjectArrayElement (new JniObjectReference (dest), i, new JniObjectReference (native)); -#else // !JAVA_INTEROP - SetObjectArrayElement (dest, i, native); -#endif // !JAVA_INTEROP DeleteLocalRef (native); } } @@ -1337,11 +972,7 @@ public static void CopyArray (IJavaObject[] src, IntPtr dest) for (int i = 0; i < src.Length; i++) { IJavaObject o = src [i]; -#if JAVA_INTEROP JniEnvironment.Arrays.SetObjectArrayElement (new JniObjectReference (dest), i, new JniObjectReference (o == null ? IntPtr.Zero : o.Handle)); -#else // !JAVA_INTEROP - SetObjectArrayElement (dest, i, o == null ? IntPtr.Zero : o.Handle); -#endif // !JAVA_INTEROP } } @@ -1526,11 +1157,7 @@ static Array _GetArray (IntPtr array_ptr, Type element_type) static int _GetArrayLength (IntPtr array_ptr) { -#if JAVA_INTEROP return JniEnvironment.Arrays.GetArrayLength (new JniObjectReference (array_ptr)); -#else // !JAVA_INTEROP - return Env.GetArrayLength (Handle, array_ptr); -#endif // !JAVA_INTEROP } public static object[] GetObjectArray (IntPtr array_ptr, Type[] element_types) @@ -1606,18 +1233,11 @@ public static unsafe IntPtr NewArray (bool[] array) if (array == null) return IntPtr.Zero; IntPtr result; -#if JAVA_INTEROP + var r = JniEnvironment.Arrays.NewBooleanArray (array.Length); fixed (bool* p = array) JniEnvironment.Arrays.SetBooleanArrayRegion (r, 0, array.Length, p); result = r.Handle; -#else // !JAVA_INTEROP - result = LogCreateLocalRef (Env.NewBooleanArray (Handle, array.Length)); - byte[] bytes = new byte [array.Length]; - for (int i = 0; i < array.Length; i++) - bytes [i] = (byte) (array [i] ? 1 : 0); - SetBooleanArrayRegion (result, 0, array.Length, bytes); -#endif // !JAVA_INTEROP return result; } @@ -1640,17 +1260,7 @@ public static IntPtr NewObjectArray (int length, IntPtr elementClass) public static IntPtr NewObjectArray (int length, IntPtr elementClass, IntPtr initialElement) { -#if JAVA_INTEROP return JniEnvironment.Arrays.NewObjectArray (length, new JniObjectReference (elementClass), new JniObjectReference (initialElement)).Handle; -#else // !JAVA_INTEROP - IntPtr result = LogCreateLocalRef (Env.NewObjectArray (Handle, length, elementClass, initialElement)); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); - - return result; -#endif // !JAVA_INTEROP } public static IntPtr NewObjectArray(params T[] values) @@ -1887,117 +1497,50 @@ static Dictionary> CreateSetNativeArrayElement static unsafe void _SetBooleanArrayRegion (IntPtr array, int start, int length, bool[] buffer) { -#if JAVA_INTEROP fixed (bool* p = buffer) JniEnvironment.Arrays.SetBooleanArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - var _buffer = new byte [buffer.Length]; - for (int i = 0; i < _buffer.Length; ++i) - _buffer [i] = buffer [i] ? (byte) 1 : (byte) 0; - Env.SetBooleanArrayRegion (Handle, array, start, length, _buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _SetByteArrayRegion (IntPtr array, int start, int length, byte[] buffer) { -#if JAVA_INTEROP fixed (byte* p = buffer) JniEnvironment.Arrays.SetByteArrayRegion (new JniObjectReference (array), start, length, (sbyte*) p); -#else // !JAVA_INTEROP - Env.SetByteArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _SetCharArrayRegion (IntPtr array, int start, int length, char[] buffer) { -#if JAVA_INTEROP fixed (char* p = buffer) JniEnvironment.Arrays.SetCharArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.SetCharArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _SetShortArrayRegion (IntPtr array, int start, int length, short[] buffer) { -#if JAVA_INTEROP fixed (short* p = buffer) JniEnvironment.Arrays.SetShortArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.SetShortArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _SetIntArrayRegion (IntPtr array, int start, int length, int[] buffer) { -#if JAVA_INTEROP fixed (int* p = buffer) JniEnvironment.Arrays.SetIntArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.SetIntArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _SetLongArrayRegion (IntPtr array, int start, int length, long[] buffer) { -#if JAVA_INTEROP fixed (long* p = buffer) JniEnvironment.Arrays.SetLongArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.SetLongArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _SetFloatArrayRegion (IntPtr array, int start, int length, float[] buffer) { -#if JAVA_INTEROP fixed (float* p = buffer) JniEnvironment.Arrays.SetFloatArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.SetFloatArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } static unsafe void _SetDoubleArrayRegion (IntPtr array, int start, int length, double[] buffer) { -#if JAVA_INTEROP fixed (double* p = buffer) JniEnvironment.Arrays.SetDoubleArrayRegion (new JniObjectReference (array), start, length, p); -#else // !JAVA_INTEROP - Env.SetDoubleArrayRegion (Handle, array, start, length, buffer); - - Exception e = AndroidEnvironment.GetExceptionForLastThrowable (); - if (e != null) - ExceptionDispatchInfo.Capture (e).Throw (); -#endif // !JAVA_INTEROP } public static void SetArrayItem (IntPtr array_ptr, int index, T value) @@ -2022,38 +1565,6 @@ public static Java.Lang.Object[] ToObjectArray (T[] array) return ret; } -#if !JAVA_INTEROP - delegate int GetEnvDelegate (IntPtr javavm, out IntPtr envptr, int version); - delegate int AttachCurrentThreadDelegate (IntPtr javavm, out IntPtr env, IntPtr args); - delegate int DetachCurrentThreadDelegate (IntPtr javavm); - - struct JNIInvokeInterface { - public IntPtr reserved0; - public IntPtr reserved1; - public IntPtr reserved2; - - public IntPtr DestroyJavaVM; // jint (*DestroyJavaVM)(JavaVM*); - public AttachCurrentThreadDelegate AttachCurrentThread; - public DetachCurrentThreadDelegate DetachCurrentThread; - public GetEnvDelegate GetEnv; - public IntPtr AttachCurrentThreadAsDaemon; //jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); - } - - internal struct JNINativeMethod { - - public string Name; - public string Sig; - public Delegate Func; - - public JNINativeMethod (string name, string sig, Delegate func) - { - Name = name; - Sig = sig; - Func = func; - } - } -#endif // !JAVA_INTEROP - #if ANDROID_8 [DllImport ("libjnigraphics.so")] static extern int AndroidBitmap_getInfo (IntPtr env, IntPtr jbitmap, out Android.Graphics.AndroidBitmapInfo info); @@ -2081,5 +1592,3 @@ internal static int AndroidBitmap_unlockPixels (IntPtr jbitmap) #endif // ANDROID_8 } } - - diff --git a/src/Mono.Android/Android.Runtime/Logger.cs b/src/Mono.Android/Android.Runtime/Logger.cs index 0a5d18d5430..e752f135241 100644 --- a/src/Mono.Android/Android.Runtime/Logger.cs +++ b/src/Mono.Android/Android.Runtime/Logger.cs @@ -3,9 +3,10 @@ namespace Android.Runtime { internal static class Logger { - internal static LogCategories Categories; static bool hasNoLibLog; + internal static LogCategories Categories; + internal static bool LogAssembly { get {return (Categories & LogCategories.Assembly) != 0;} } @@ -58,18 +59,28 @@ public static void Log (LogLevel level, string appname, string log) { System.Console.WriteLine ("[{0}] {1}: {2}", level, appname, line); } } + + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + extern static uint monodroid_get_log_categories (); + + static Logger () + { + Categories = (LogCategories) monodroid_get_log_categories (); + } } + // Keep in sync with the LogLevel enum in + // monodroid/libmonodroid/logger.{c,h} internal enum LogLevel { - Unknown, - Default, - Verbose, - Debug, - Info, - Warn, - Error, - Fatal, - Silent + Unknown = 0x00, + Default = 0x01, + Verbose = 0x02, + Debug = 0x03, + Info = 0x04, + Warn = 0x05, + Error = 0x06, + Fatal = 0x07, + Silent = 0x08 } // Keep in sync with the LogCategories enum in diff --git a/src/Mono.Android/Android.Runtime/UncaughtExceptionHandler.cs b/src/Mono.Android/Android.Runtime/UncaughtExceptionHandler.cs index 871134bdc80..57cd49911a1 100644 --- a/src/Mono.Android/Android.Runtime/UncaughtExceptionHandler.cs +++ b/src/Mono.Android/Android.Runtime/UncaughtExceptionHandler.cs @@ -5,27 +5,9 @@ namespace Android.Runtime { sealed class UncaughtExceptionHandler : Java.Lang.Object, Java.Lang.Thread.IUncaughtExceptionHandler { - static Action mono_unhandled_exception; + Action mono_unhandled_exception; - static Action AppDomain_DoUnhandledException; - - static UncaughtExceptionHandler () - { - var mono_UnhandledException = typeof (System.Diagnostics.Debugger) - .GetMethod ("Mono_UnhandledException", BindingFlags.NonPublic | BindingFlags.Static); - mono_unhandled_exception = (Action) Delegate.CreateDelegate (typeof(Action), mono_UnhandledException); - - var ad_due = typeof (AppDomain) - .GetMethod ("DoUnhandledException", - bindingAttr: BindingFlags.NonPublic | BindingFlags.Instance, - binder: null, - types: new []{typeof (UnhandledExceptionEventArgs)}, - modifiers: null); - if (ad_due != null) { - AppDomain_DoUnhandledException = (Action) Delegate.CreateDelegate ( - typeof (Action), ad_due); - } - } + Action AppDomain_DoUnhandledException; Java.Lang.Thread.IUncaughtExceptionHandler defaultHandler; @@ -40,6 +22,12 @@ internal Java.Lang.Thread.IUncaughtExceptionHandler DefaultHandler { public void UncaughtException (Java.Lang.Thread thread, Java.Lang.Throwable ex) { + try { + Initialize (); + } catch (Exception e) { + Android.Runtime.AndroidEnvironment.FailFast ($"Unable to initialize UncaughtExceptionHandler. Nested exception caught: {e}"); + } + mono_unhandled_exception (ex); if (AppDomain_DoUnhandledException != null) { try { @@ -55,5 +43,27 @@ public void UncaughtException (Java.Lang.Thread thread, Java.Lang.Throwable ex) if (defaultHandler != null) defaultHandler.UncaughtException (thread, ex); } + + void Initialize () + { + if (mono_unhandled_exception == null) { + var mono_UnhandledException = typeof (System.Diagnostics.Debugger) + .GetMethod ("Mono_UnhandledException", BindingFlags.NonPublic | BindingFlags.Static); + mono_unhandled_exception = (Action) Delegate.CreateDelegate (typeof(Action), mono_UnhandledException); + } + + if (AppDomain_DoUnhandledException == null) { + var ad_due = typeof (AppDomain) + .GetMethod ("DoUnhandledException", + bindingAttr: BindingFlags.NonPublic | BindingFlags.Instance, + binder: null, + types: new []{typeof (UnhandledExceptionEventArgs)}, + modifiers: null); + if (ad_due != null) { + AppDomain_DoUnhandledException = (Action) Delegate.CreateDelegate ( + typeof (Action), ad_due); + } + } + } } } diff --git a/src/Mono.Android/Java.Interop/Runtime.cs b/src/Mono.Android/Java.Interop/Runtime.cs index 7cfa945db63..b4e28f584fa 100644 --- a/src/Mono.Android/Java.Interop/Runtime.cs +++ b/src/Mono.Android/Java.Interop/Runtime.cs @@ -8,21 +8,19 @@ namespace Java.Interop { public static class Runtime { - internal static IntPtr grefIGCUserPeer_class; - public static List GetSurfacedObjects () { return Java.Lang.Object.GetSurfacedObjects_ForDiagnosticsOnly (); } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_max_gref_get (); public static int MaxGlobalReferenceCount { get {return _monodroid_max_gref_get ();} } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_gref_get (); public static int GlobalReferenceCount { @@ -46,10 +44,7 @@ public static bool IsGCUserPeer (IJavaObject value) public static bool IsGCUserPeer (IntPtr value) { - if (value == IntPtr.Zero) - return false; - - return JNIEnv.IsInstanceOf (value, grefIGCUserPeer_class); + return JNIEnv.IsGCUserPeer (value); } } } diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index 49d4108eb13..98efa0c5a09 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -9,48 +9,51 @@ namespace Java.Interop { - public static partial class TypeManager { - - // Make this internal so that JNIEnv.Initialize can trigger the static - // constructor so that JNIEnv.RegisterJNINatives() doesn't include - // the static constructor execution. - - // Lock on jniToManaged before accessing EITHER jniToManaged or managedToJni. - internal static Dictionary jniToManaged = new Dictionary (); - static Dictionary managedToJni = new Dictionary (); - - internal static IntPtr id_Class_getName; - - static TypeManager () - { - var start = new DateTime (); - if (Logger.LogTiming) { - start = DateTime.UtcNow; - Logger.Log (LogLevel.Info, - "monodroid-timing", - "TypeManager.cctor start: " + (start - new DateTime (1970, 1, 1)).TotalMilliseconds); + static class TypeManagerMapDictionaries + { + static Dictionary _jniToManaged; + static Dictionary _managedToJni; + + public static readonly object AccessLock = new object (); + + // + // Access to both properties MUST be done after taking lock on accessLock! + // + public static Dictionary JniToManaged { + get { + if (_jniToManaged == null) + _jniToManaged = new Dictionary (); + return _jniToManaged; } + } - __TypeRegistrations.RegisterPackages (); - - if (Logger.LogTiming) { - var end = DateTime.UtcNow; - Logger.Log (LogLevel.Info, - "monodroid-timing", - "TypeManager.cctor time: " + (end - new DateTime (1970, 1, 1)).TotalMilliseconds + " [elapsed: " + (end - start).TotalMilliseconds + " ms]"); + public static Dictionary ManagedToJni { + get { + if (_managedToJni == null) + _managedToJni = new Dictionary (); + return _managedToJni; } } + } + + public static partial class TypeManager { + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + extern static IntPtr monodroid_TypeManager_get_java_class_name (IntPtr klass); internal static string GetClassName (IntPtr class_ptr) { - return JNIEnv.GetString (JNIEnv.CallObjectMethod (class_ptr, JNIEnv.mid_Class_getName), JniHandleOwnership.TransferLocalRef).Replace (".", "/"); + IntPtr ptr = monodroid_TypeManager_get_java_class_name (class_ptr); + string ret = Marshal.PtrToStringAnsi (ptr); + JNIEnv.monodroid_free (ptr); + + return ret; } internal static string GetJniTypeName (Type type) { string jni; - lock (jniToManaged) { - if (managedToJni.TryGetValue (type, out jni)) + lock (TypeManagerMapDictionaries.AccessLock) { + if (TypeManagerMapDictionaries.ManagedToJni.TryGetValue (type, out jni)) return jni; } return null; @@ -200,7 +203,7 @@ static Exception CreateJavaLocationException () return new JavaLocationException (loc.ToString ()); } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr monodroid_typemap_java_to_managed (string java); internal static Type GetJavaToManagedType (string class_name) @@ -213,6 +216,8 @@ internal static Type GetJavaToManagedType (string class_name) return null; } + __TypeRegistrations.RegisterPackages (); + var type = (Type) null; int ls = class_name.LastIndexOf ('/'); var package = ls >= 0 ? class_name.Substring (0, ls) : ""; @@ -241,12 +246,12 @@ internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership tr Type type = null; IntPtr class_ptr = JNIEnv.GetObjectClass (handle); string class_name = GetClassName (class_ptr); - lock (jniToManaged) { - while (class_ptr != IntPtr.Zero && !jniToManaged.TryGetValue (class_name, out type)) { + lock (TypeManagerMapDictionaries.AccessLock) { + while (class_ptr != IntPtr.Zero && !TypeManagerMapDictionaries.JniToManaged.TryGetValue (class_name, out type)) { type = GetJavaToManagedType (class_name); if (type != null) { - jniToManaged.Add (class_name, type); + TypeManagerMapDictionaries.JniToManaged.Add (class_name, type); break; } @@ -256,7 +261,7 @@ internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership tr class_name = GetClassName (class_ptr); } } - + JNIEnv.DeleteLocalRef (class_ptr); if (type == null) { @@ -269,7 +274,7 @@ internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership tr if (targetType != null && !targetType.IsAssignableFrom (type)) type = targetType; - + if (type.IsInterface || type.IsAbstract) { var invokerType = JavaObjectExtensions.GetHelperType (type, "Invoker"); if (invokerType == null) @@ -314,12 +319,12 @@ internal static object CreateProxy (Type type, IntPtr handle, JniHandleOwnership public static void RegisterType (string java_class, Type t) { string jniFromType = JNIEnv.GetJniName (t); - lock (jniToManaged) { + lock (TypeManagerMapDictionaries.AccessLock) { Type lookup; - if (!jniToManaged.TryGetValue (java_class, out lookup)) { - jniToManaged.Add (java_class, t); - if (jniFromType != java_class) { - managedToJni.Add (t, java_class); + if (!TypeManagerMapDictionaries.JniToManaged.TryGetValue (java_class, out lookup)) { + TypeManagerMapDictionaries.JniToManaged.Add (java_class, t); + if (String.Compare (jniFromType, java_class, StringComparison.OrdinalIgnoreCase) != 0) { + TypeManagerMapDictionaries.ManagedToJni.Add (t, java_class); } } else if (!JNIEnv.IsRunningOnDesktop || t != typeof (Java.Interop.TypeManager)) { // skip the registration and output a warning diff --git a/src/Mono.Android/Test/Java.Interop/JnienvTest.cs b/src/Mono.Android/Test/Java.Interop/JnienvTest.cs index e5e9f236590..a4f90046cba 100644 --- a/src/Mono.Android/Test/Java.Interop/JnienvTest.cs +++ b/src/Mono.Android/Test/Java.Interop/JnienvTest.cs @@ -373,7 +373,7 @@ public void MoarThreadingTests () Assert.IsNull (ignore_t2, string.Format ("No exception should be thrown [t2]! Got: {0}", ignore_t2)); } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr monodroid_typemap_java_to_managed (string java); [Test] @@ -385,7 +385,7 @@ public void JavaToManagedTypeMapping () Assert.AreEqual (IntPtr.Zero, m); } - [DllImport ("__Internal")] + [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr monodroid_typemap_managed_to_java (string java); string GetTypeName (Type type) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index dfc59a14d01..8089c2d1da9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -105,7 +105,7 @@ public override bool RunTask () void Run (DirectoryAssemblyResolver res) { PackageNamingPolicy pnp; - JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse (PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash; + JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse (PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseCrc64; foreach (var dir in FrameworkDirectories) { if (Directory.Exists (dir.ItemSpec)) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 3e6873a4b5b..d2ae33d60ba 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -9,10 +9,13 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using Java.Interop.Tools.TypeNameMappings; using Xamarin.Android.Tools; namespace Xamarin.Android.Tasks { + using PackageNamingPolicyEnum = PackageNamingPolicy; + public class GeneratePackageManagerJava : AndroidTask { public override string TaskPrefix => "GPM"; @@ -55,6 +58,7 @@ public class GeneratePackageManagerJava : AndroidTask [Required] public bool EnablePreloadAssembliesDefault { get; set; } + public string PackageNamingPolicy { get; set; } public string Debug { get; set; } public ITaskItem[] Environments { get; set; } public string AndroidAotMode { get; set; } @@ -141,11 +145,16 @@ void AddEnvironment () { bool usesMonoAOT = false; bool usesAssemblyPreload = EnablePreloadAssembliesDefault; + bool brokenExceptionTransitions = false; uint monoAOTMode = 0; string androidPackageName = null; var environmentVariables = new Dictionary (StringComparer.Ordinal); var systemProperties = new Dictionary (StringComparer.Ordinal); + if (!Enum.TryParse (PackageNamingPolicy, out PackageNamingPolicy pnp)) { + pnp = PackageNamingPolicyEnum.LowercaseCrc64; + } + AotMode aotMode; if (AndroidAotMode != null && Aot.GetAndroidAotMode (AndroidAotMode, out aotMode)) { usesMonoAOT = true; @@ -189,6 +198,10 @@ void AddEnvironment () } continue; } + if (lineToWrite.StartsWith ("XA_BROKEN_EXCEPTION_TRANSITIONS=")) { + brokenExceptionTransitions = true; + continue; + } AddEnvironmentVariableLine (lineToWrite); } @@ -260,6 +273,8 @@ void AddEnvironment () UsesAssemblyPreload = usesAssemblyPreload, MonoAOTMode = monoAOTMode.ToString ().ToLowerInvariant (), AndroidPackageName = AndroidPackageName, + BrokenExceptionTransitions = brokenExceptionTransitions, + PackageNamingPolicy = pnp, }; using (var sw = new StreamWriter (ms, utf8Encoding, bufferSize: 8192, leaveOpen: true)) { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs index 817dfe23262..5f9f49995d1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs @@ -21,11 +21,13 @@ public sealed class ApplicationConfig public bool uses_mono_aot; public bool uses_assembly_preload; public bool is_a_bundled_app; + public bool broken_exception_transitions; + public uint package_naming_policy; public uint environment_variable_count; public uint system_property_count; public string android_package_name; }; - const uint ApplicationConfigFieldCount = 7; + const uint ApplicationConfigFieldCount = 9; static readonly object ndkInitLock = new object (); static readonly char[] readElfFieldSeparator = new [] { ' ', '\t' }; @@ -128,17 +130,27 @@ static ApplicationConfig ReadApplicationConfig (string envFile) ret.is_a_bundled_app = ConvertFieldToBool ("is_a_bundled_app", envFile, i, field [1]); break; - case 4: // environment_variable_count: uint32_t / .word | .long + case 4: // broken_exception_transitions: bool / .byte + AssertFieldType (envFile, ".byte", field [0], i); + ret.broken_exception_transitions = ConvertFieldToBool ("broken_exception_transitions", envFile, i, field [1]); + break; + + case 5: // package_naming_policy: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile}:{i}': {field [0]}"); + ret.package_naming_policy = ConvertFieldToUInt32 ("package_naming_policy", envFile, i, field [1]); + break; + + case 6: // environment_variable_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile}:{i}': {field [0]}"); ret.environment_variable_count = ConvertFieldToUInt32 ("environment_variable_count", envFile, i, field [1]); break; - case 5: // system_property_count: uint32_t / .word | .long + case 7: // system_property_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile}:{i}': {field [0]}"); ret.system_property_count = ConvertFieldToUInt32 ("system_property_count", envFile, i, field [1]); break; - case 6: // android_package_name: string / [pointer type] + case 8: // android_package_name: string / [pointer type] Assert.IsTrue (expectedPointerTypes.Contains (field [0]), $"Unexpected pointer field type in '{envFile}:{i}': {field [0]}"); pointers.Add (field [1].Trim ()); break; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs index d33e15f2103..eea7e797f45 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; +using Java.Interop.Tools.TypeNameMappings; + namespace Xamarin.Android.Tasks { class ApplicationConfigNativeAssemblyGenerator : NativeAssemblyGenerator @@ -16,6 +18,8 @@ class ApplicationConfigNativeAssemblyGenerator : NativeAssemblyGenerator public bool UsesAssemblyPreload { get; set; } public string MonoAOTMode { get; set; } public string AndroidPackageName { get; set; } + public bool BrokenExceptionTransitions { get; set; } + public PackageNamingPolicy PackageNamingPolicy { get; set; } public ApplicationConfigNativeAssemblyGenerator (NativeAssemblerTargetProvider targetProvider, IDictionary environmentVariables, IDictionary systemProperties) : base (targetProvider) @@ -53,6 +57,12 @@ protected override void WriteSymbols (StreamWriter output) WriteCommentLine (output, "is_a_bundled_app"); size += WriteData (output, IsBundledApp); + WriteCommentLine (output, "broken_exception_transitions"); + size += WriteData (output, BrokenExceptionTransitions); + + WriteCommentLine (output, "package_naming_policy"); + size += WriteData (output, (uint)PackageNamingPolicy); + WriteCommentLine (output, "environment_variable_count"); size += WriteData (output, environmentVariables == null ? 0 : environmentVariables.Count * 2); diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 53b56658493..95ef8d182c0 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2313,6 +2313,7 @@ because xbuild doesn't support framework reference assemblies. SupportedAbis="@(_BuildTargetAbis)" AndroidPackageName="$(_AndroidPackage)" EnablePreloadAssembliesDefault="$(_AndroidEnablePreloadAssembliesDefault)" + PackageNamingPolicy="$(AndroidPackageNamingPolicy)" > diff --git a/src/java-runtime/java/mono/android/MonoPackageManager.java b/src/java-runtime/java/mono/android/MonoPackageManager.java index 1ac3c9987d8..80d266ce62b 100644 --- a/src/java-runtime/java/mono/android/MonoPackageManager.java +++ b/src/java-runtime/java/mono/android/MonoPackageManager.java @@ -10,6 +10,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.res.AssetManager; +import android.os.Build; import android.util.Log; import mono.android.Runtime; import mono.android.DebugRuntime; @@ -78,6 +79,7 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack System.loadLibrary("xamarin-app"); System.loadLibrary("monodroid"); + Runtime.initInternal ( language, apks, @@ -86,8 +88,9 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack loader, externalStorageDirs, MonoPackageManager_Resources.Assemblies, - android.os.Build.VERSION.SDK_INT, - embeddedDSOsEnabled + Build.VERSION.SDK_INT, + embeddedDSOsEnabled, + isEmulator () ); mono.android.app.ApplicationRegistration.registerApplications (); @@ -97,6 +100,22 @@ public static void LoadApplication (Context context, ApplicationInfo runtimePack } } + // We need to detect the emulator in order to determine the maximum gref count. + // The official Android emulator requires a much lower maximum than actual + // devices. Hopefully other emulators don't need the treatment. If they do, we + // can add their detection here. We should perform the absolute minimum of + // checking in order to save time. + static boolean isEmulator() + { + String val = Build.HARDWARE; + + // This detects the official Android emulator + if (val.contains ("ranchu") || val.contains ("goldfish")) + return true; + + return false; + } + public static void setContext (Context context) { // Ignore; vestigial diff --git a/src/java-runtime/java/mono/android/Runtime.java b/src/java-runtime/java/mono/android/Runtime.java index 61377b01a35..9623f1d6acf 100644 --- a/src/java-runtime/java/mono/android/Runtime.java +++ b/src/java-runtime/java/mono/android/Runtime.java @@ -12,7 +12,7 @@ private Runtime () } public static native void init (String lang, String[] runtimeApks, String runtimeDataDir, String[] appDirs, ClassLoader loader, String[] externalStorageDirs, String[] assemblies, String packageName, int apiLevel, String[] environmentVariables); - public static native void initInternal (String lang, String[] runtimeApks, String runtimeDataDir, String[] appDirs, ClassLoader loader, String[] externalStorageDirs, String[] assemblies, int apiLevel, boolean embeddedDSOsEnabled); + public static native void initInternal (String lang, String[] runtimeApks, String runtimeDataDir, String[] appDirs, ClassLoader loader, String[] externalStorageDirs, String[] assemblies, int apiLevel, boolean embeddedDSOsEnabled, boolean isEmulator); public static native void register (String managedType, java.lang.Class nativeClass, String methods); public static native void notifyTimeZoneChanged (); public static native int createNewContext (String[] runtimeApks, String[] assemblies, ClassLoader loader); diff --git a/src/monodroid/jni/android-system.cc b/src/monodroid/jni/android-system.cc index 7213c1e37a2..3311c3bbe17 100644 --- a/src/monodroid/jni/android-system.cc +++ b/src/monodroid/jni/android-system.cc @@ -515,15 +515,10 @@ AndroidSystem::count_override_assemblies (void) long AndroidSystem::get_max_gref_count_from_system (void) { - constexpr char HARDWARE_TYPE[] = "ro.hardware"; - constexpr char HARDWARE_EMULATOR[] = "goldfish"; - long max; - char value [PROP_VALUE_MAX+1]; char *override; - int len = _monodroid__system_property_get (HARDWARE_TYPE, value, sizeof (value)); - if (len > 0 && strcmp (value, HARDWARE_EMULATOR) == 0) { + if (running_in_emulator) { max = 2000; } else { max = 51200; diff --git a/src/monodroid/jni/android-system.hh b/src/monodroid/jni/android-system.hh index 94a80c4381c..e7b5685d390 100644 --- a/src/monodroid/jni/android-system.hh +++ b/src/monodroid/jni/android-system.hh @@ -87,6 +87,11 @@ namespace xamarin { namespace android { namespace internal return aotMode; } + void set_running_in_emulator (bool yesno) + { + running_in_emulator = yesno; + } + private: #if defined (DEBUG) || !defined (ANDROID) void add_system_property (const char *name, const char *value); @@ -120,6 +125,7 @@ namespace xamarin { namespace android { namespace internal private: long max_gref_count = 0; MonoAotMode aotMode = MonoAotMode::MONO_AOT_MODE_NONE; + bool running_in_emulator = false; }; }}} #endif // !__ANDROID_SYSTEM_H diff --git a/src/monodroid/jni/application_dso_stub.cc b/src/monodroid/jni/application_dso_stub.cc index 94f91504295..45429b2dfc3 100644 --- a/src/monodroid/jni/application_dso_stub.cc +++ b/src/monodroid/jni/application_dso_stub.cc @@ -17,6 +17,8 @@ ApplicationConfig application_config = { .uses_mono_aot = false, .uses_assembly_preload = false, .is_a_bundled_app = false, + .broken_exception_transitions = false, + .package_naming_policy = 0, .environment_variable_count = 0, .system_property_count = 0, .android_package_name = "com.xamarin.test", diff --git a/src/monodroid/jni/external-api.cc b/src/monodroid/jni/external-api.cc index 81d30891a85..0ad9c9badd8 100644 --- a/src/monodroid/jni/external-api.cc +++ b/src/monodroid/jni/external-api.cc @@ -8,7 +8,9 @@ #endif #include "globals.hh" +#include "timing.hh" +using namespace xamarin::android; using namespace xamarin::android::internal; /* Invoked by System.Core.dll!System.IO.MemoryMappedFiles.MemoryMapImpl.getpagesize */ @@ -174,6 +176,40 @@ MONO_API int monodroid_embedded_assemblies_set_assemblies_prefix (const char *pr return 0; } +MONO_API managed_timing_sequence* +monodroid_timing_start (const char *message) +{ + if (timing == nullptr) + return nullptr; + + managed_timing_sequence *ret = timing->get_available_sequence (); + if (message != nullptr) { + log_info (LOG_TIMING, message); + } + ret->period.mark_start (); + + return ret; +} + +MONO_API void +monodroid_timing_stop (managed_timing_sequence *sequence, const char *message) +{ + static constexpr const char DEFAULT_MESSAGE[] = "Managed Timing"; + + if (sequence == nullptr) + return; + + sequence->period.mark_end (); + Timing::info (sequence->period, message == nullptr ? DEFAULT_MESSAGE : message); + timing->release_sequence (sequence); +} + +MONO_API char* +monodroid_TypeManager_get_java_class_name (jclass klass) +{ + return monodroidRuntime.get_java_class_name_for_TypeManager (klass); +} + extern "C" void* monodroid_dylib_mono_new (const char *libmono_path) { return nullptr; diff --git a/src/monodroid/jni/globals.cc b/src/monodroid/jni/globals.cc index c9248956fb7..2a405b86977 100644 --- a/src/monodroid/jni/globals.cc +++ b/src/monodroid/jni/globals.cc @@ -8,6 +8,7 @@ AndroidSystem androidSystem; OSBridge osBridge; EmbeddedAssemblies embeddedAssemblies; MonodroidRuntime monodroidRuntime; +Timing *timing = nullptr; #ifndef ANDROID InMemoryAssemblies inMemoryAssemblies; #endif diff --git a/src/monodroid/jni/globals.hh b/src/monodroid/jni/globals.hh index b61f40baef6..82d16fbe496 100644 --- a/src/monodroid/jni/globals.hh +++ b/src/monodroid/jni/globals.hh @@ -3,6 +3,7 @@ #define __GLOBALS_H #include "util.hh" +#include "timing.hh" #include "debug.hh" #include "embedded-assemblies.hh" #include "inmemory-assemblies.hh" @@ -15,6 +16,8 @@ extern xamarin::android::internal::AndroidSystem androidSystem; extern xamarin::android::internal::OSBridge osBridge; extern xamarin::android::internal::EmbeddedAssemblies embeddedAssemblies; extern xamarin::android::internal::MonodroidRuntime monodroidRuntime; +extern xamarin::android::Timing *timing; + #ifndef ANDROID extern xamarin::android::internal::InMemoryAssemblies inMemoryAssemblies; #endif diff --git a/src/monodroid/jni/logger.cc b/src/monodroid/jni/logger.cc index b464d2020f8..1bc3a8f2842 100644 --- a/src/monodroid/jni/logger.cc +++ b/src/monodroid/jni/logger.cc @@ -41,6 +41,20 @@ static const char* log_names[] = { "*error*", }; +// Keep in sync with LogLevel defined in JNIEnv.cs +enum class LogLevel : unsigned int +{ + Unknown = 0x00, + Default = 0x01, + Verbose = 0x02, + Debug = 0x03, + Info = 0x04, + Warn = 0x05, + Error = 0x06, + Fatal = 0x07, + Silent = 0x08 +}; + #if defined(__i386__) && defined(__GNUC__) #define ffs(__value__) __builtin_ffs ((__value__)) #elif defined(__x86_64__) && defined(__GNUC__) @@ -236,3 +250,49 @@ log_debug_nocheck (LogCategories category, const char *format, ...) DO_LOG (ANDROID_LOG_DEBUG, category, format, args); } + +// +// DO NOT REMOVE: used by Android.Runtime.Logger +// +MONO_API unsigned int +monodroid_get_log_categories () +{ + return log_categories; +} + +// +// DO NOT REMOVE: used by Android.Runtime.JNIEnv +// +MONO_API void +monodroid_log (LogLevel level, LogCategories category, const char *message) +{ + switch (level) { + case LogLevel::Verbose: + case LogLevel::Debug: + log_debug_nocheck (category, message); + break; + + case LogLevel::Info: + log_info_nocheck (category, message); + break; + + case LogLevel::Warn: + case LogLevel::Silent: // warn is always printed + log_warn (category, message); + break; + + case LogLevel::Error: + log_error (category, message); + break; + + case LogLevel::Fatal: + log_fatal (category, message); + break; + + default: + case LogLevel::Unknown: + case LogLevel::Default: + log_info_nocheck (category, message); + break; + } +} diff --git a/src/monodroid/jni/mono_android_Runtime.h b/src/monodroid/jni/mono_android_Runtime.h index 08cfc2d1c06..09974415604 100644 --- a/src/monodroid/jni/mono_android_Runtime.h +++ b/src/monodroid/jni/mono_android_Runtime.h @@ -21,7 +21,7 @@ JNIEXPORT void JNICALL Java_mono_android_Runtime_init * Signature: (Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/ClassLoader;[Ljava/lang/String;[Ljava/lang/String;IZ)V */ JNIEXPORT void JNICALL Java_mono_android_Runtime_initInternal - (JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jobject, jobjectArray, jobjectArray, jint, jboolean); +(JNIEnv *, jclass, jstring, jobjectArray, jstring, jobjectArray, jobject, jobjectArray, jobjectArray, jint, jboolean, jboolean); /* * Class: mono_android_Runtime diff --git a/src/monodroid/jni/monodroid-glue-internal.hh b/src/monodroid/jni/monodroid-glue-internal.hh index 1fc10f3ef97..95eb09b4ac6 100644 --- a/src/monodroid/jni/monodroid-glue-internal.hh +++ b/src/monodroid/jni/monodroid-glue-internal.hh @@ -5,6 +5,7 @@ #include #include "android-system.hh" #include "osbridge.hh" +#include "timing.hh" #include #include @@ -32,13 +33,14 @@ namespace xamarin::android::internal jclass grefClass; jmethodID Class_forName; unsigned int logCategories; - jmethodID Class_getName; int version; int androidSdkVersion; int localRefsAreIndirect; int grefGcThreshold; jobject grefIGCUserPeer; int isRunningOnDesktop; + uint8_t brokenExceptionTransitions; + int packageNamingPolicy; }; private: @@ -59,7 +61,7 @@ namespace xamarin::android::internal void Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader, jobjectArray externalStorageDirs, jobjectArray assembliesJava, - jint apiLevel, jboolean embeddedDSOsEnabled); + jint apiLevel, jboolean embeddedDSOsEnabled, jboolean isEmulator); jint Java_mono_android_Runtime_createNewContextWithData (JNIEnv *env, jclass klass, jobjectArray runtimeApksJava, jobjectArray assembliesJava, jobjectArray assembliesBytes, jobject loader, jboolean force_preload_assemblies); void Java_mono_android_Runtime_switchToContext (JNIEnv *env, jclass klass, jint contextID); @@ -112,10 +114,11 @@ namespace xamarin::android::internal // in turn is internally defined by clang to be `char*` // // Desktop builds (using both clang++ and g++) do NOT appear to have this issue, so it might be a problem in the - // NDK. More investigation would be required, but for now lets work around the issue by not overloading the + // NDK. More investigation would be required, but for now lets work around the issue by not overloading the // function void dump_counters (const char *format, ...); void dump_counters_v (const char *format, va_list args); + char* get_java_class_name_for_TypeManager (jclass klass); private: int convert_dl_flags (int flags); @@ -186,6 +189,7 @@ namespace xamarin::android::internal volatile bool monodroid_gdb_wait = true; jclass java_System; jmethodID java_System_identityHashCode; + jmethodID Class_getName; jclass java_TimeZone; timing_period jit_time; FILE *jit_log; diff --git a/src/monodroid/jni/monodroid-glue.cc b/src/monodroid/jni/monodroid-glue.cc index 78b5717a250..b06cae05025 100644 --- a/src/monodroid/jni/monodroid-glue.cc +++ b/src/monodroid/jni/monodroid-glue.cc @@ -69,6 +69,7 @@ #include "monodroid-glue-internal.hh" #include "globals.hh" #include "xamarin-app.h" +#include "timing.hh" #ifndef WINDOWS #include "xamarin_getifaddrs.h" @@ -906,8 +907,28 @@ MonodroidRuntime::lookup_bridge_info (MonoDomain *domain, MonoImage *image, cons void MonodroidRuntime::init_android_runtime (MonoDomain *domain, JNIEnv *env, jclass runtimeClass, jobject loader) { + struct JnienvInitializeArgs init = {}; + init.javaVm = osBridge.get_jvm (); + init.env = env; + init.logCategories = log_categories; + init.version = env->GetVersion (); + init.androidSdkVersion = android_api_level; + init.localRefsAreIndirect = LocalRefsAreIndirect (env, runtimeClass, init.androidSdkVersion); + init.isRunningOnDesktop = is_running_on_desktop ? 1 : 0; + init.brokenExceptionTransitions = application_config.broken_exception_transitions ? 1 : 0; + init.packageNamingPolicy = application_config.package_naming_policy; + + // GC threshold is 90% of the max GREF count + init.grefGcThreshold = static_cast(androidSystem.get_gref_gc_threshold ()); + + log_warn (LOG_GC, "GREF GC Threshold: %i", init.grefGcThreshold); + + init.grefClass = utils.get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); + Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); + init.Class_forName = env->GetStaticMethodID (init.grefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); + MonoAssembly *assm = utils.monodroid_load_assembly (domain, "Mono.Android"); - MonoImage *image = mono_assembly_get_image (assm); + MonoImage *image = mono_assembly_get_image (assm); for (uint32_t i = 0; i < OSBridge::NUM_GC_BRIDGE_TYPES; ++i) { lookup_bridge_info (domain, image, &osBridge.get_java_gc_bridge_type (i), &osBridge.get_java_gc_bridge_info (i)); @@ -939,28 +960,11 @@ MonodroidRuntime::init_android_runtime (MonoDomain *domain, JNIEnv *env, jclass } jclass lrefLoaderClass = env->GetObjectClass (loader); - - JnienvInitializeArgs init; - init.javaVm = osBridge.get_jvm (); - init.env = env; - init.logCategories = log_categories; - init.version = env->GetVersion (); - init.androidSdkVersion = android_api_level; - init.localRefsAreIndirect = LocalRefsAreIndirect (env, runtimeClass, init.androidSdkVersion); - init.isRunningOnDesktop = is_running_on_desktop; - - // GC threshold is 90% of the max GREF count - init.grefGcThreshold = static_cast(androidSystem.get_gref_gc_threshold ()); - init.grefClass = utils.get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); - init.Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); - init.Class_forName = env->GetStaticMethodID (init.grefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); init.Loader_loadClass = env->GetMethodID (lrefLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - init.grefLoader = env->NewGlobalRef (loader); - init.grefIGCUserPeer = utils.get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true); - env->DeleteLocalRef (lrefLoaderClass); - log_warn (LOG_GC, "GREF GC Threshold: %i", init.grefGcThreshold); + init.grefLoader = env->NewGlobalRef (loader); + init.grefIGCUserPeer = utils.get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true); osBridge.initialize_on_runtime_init (env, runtimeClass); @@ -977,9 +981,7 @@ MonodroidRuntime::init_android_runtime (MonoDomain *domain, JNIEnv *env, jclass if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) { partial_time.mark_end (); - - timing_diff diff (partial_time); - log_info_nocheck (LOG_TIMING, "Runtime.init: end native-to-managed transition; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns); + Timing::info (partial_time, "Runtime.init: end native-to-managed transition"); } } @@ -1320,9 +1322,7 @@ MonodroidRuntime::load_assembly (MonoDomain *domain, JNIEnv *env, jstring_wrappe if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) { total_time.mark_end (); - - timing_diff diff (total_time); - log_info (LOG_TIMING, "Assembly load: %s preloaded; elapsed: %lis:%lu::%lu", assm_name, diff.sec, diff.ms, diff.ns); + TIMING_LOG_INFO (total_time, "Assembly load: %s preloaded", assm_name); } } @@ -1342,8 +1342,7 @@ MonodroidRuntime::load_assemblies (MonoDomain *domain, JNIEnv *env, jstring_arra if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) { total_time.mark_end (); - timing_diff diff (total_time); - log_info (LOG_TIMING, "Finished loading assemblies: preloaded %u assemblies; wasted time: %lis:%lu::%lu", assemblies.get_length (), diff.sec, diff.ms, diff.ns); + TIMING_LOG_INFO (total_time, "Finished loading assemblies: preloaded %u assemblies", assemblies.get_length ()); } } @@ -1384,17 +1383,19 @@ inline void MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader, jobjectArray externalStorageDirs, jobjectArray assembliesJava, - jint apiLevel, jboolean embeddedDSOsEnabled) + jint apiLevel, jboolean embeddedDSOsEnabled, jboolean isEmulator) { init_logging_categories (); timing_period total_time; if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) { + timing = new Timing (); total_time.mark_start (); } android_api_level = apiLevel; androidSystem.set_embedded_dso_mode_enabled ((bool) embeddedDSOsEnabled); + androidSystem.set_running_in_emulator (isEmulator); java_TimeZone = utils.get_class_from_runtime_field (env, klass, "java_util_TimeZone", true); @@ -1509,8 +1510,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) { partial_time.mark_end (); - timing_diff diff (partial_time); - log_info_nocheck (LOG_TIMING, "Runtime.init: Mono runtime init; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns); + Timing::info (partial_time, "Runtime.init: Mono runtime init"); } jstring_array_wrapper assemblies (env, assembliesJava); @@ -1528,8 +1528,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) { total_time.mark_end (); - timing_diff diff (total_time); - log_info_nocheck (LOG_TIMING, "Runtime.init: end, total time; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns); + Timing::info (total_time, "Runtime.init: end, total time"); dump_counters ("## Runtime.init: end"); } } @@ -1585,7 +1584,8 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject externalStorageDirs, assembliesJava, apiLevel, - /* embeddedDSOsEnabled */ JNI_FALSE + /* embeddedDSOsEnabled */ JNI_FALSE, + /* isEmulator */ JNI_FALSE ); } @@ -1593,7 +1593,7 @@ JNIEXPORT void JNICALL Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava, jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader, jobjectArray externalStorageDirs, jobjectArray assembliesJava, - jint apiLevel, jboolean embeddedDSOsEnabled) + jint apiLevel, jboolean embeddedDSOsEnabled, jboolean isEmulator) { monodroidRuntime.Java_mono_android_Runtime_initInternal ( env, @@ -1606,7 +1606,8 @@ Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass klass, jstring lang, externalStorageDirs, assembliesJava, apiLevel, - embeddedDSOsEnabled + embeddedDSOsEnabled, + isEmulator ); } @@ -1650,14 +1651,13 @@ MonodroidRuntime::Java_mono_android_Runtime_register (JNIEnv *env, jclass klass, if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) { total_time.mark_end (); - timing_diff diff (total_time); - const char *mt_ptr = env->GetStringUTFChars (managedType, nullptr); char *type = utils.strdup_new (mt_ptr); env->ReleaseStringUTFChars (managedType, mt_ptr); - log_info_nocheck (LOG_TIMING, "Runtime.register: end time; elapsed: %lis:%lu::%lu", diff.sec, diff.ms, diff.ns); - log_warn (LOG_DEFAULT, "type == %s", type == nullptr ? "" : type); + log_info_nocheck (LOG_TIMING, "Runtime.register: registered type '%s'", type); + Timing::info (total_time, "Runtime.register: end time"); + dump_counters ("## Runtime.register: type=%s\n", type); delete[] type; } @@ -1759,6 +1759,29 @@ MonodroidRuntime::Java_mono_android_Runtime_destroyContexts (JNIEnv *env, jclass log_info (LOG_DEFAULT, "All domain cleaned up"); } +char* +MonodroidRuntime::get_java_class_name_for_TypeManager (jclass klass) +{ + if (klass == nullptr || Class_getName == nullptr) + return nullptr; + + JNIEnv *env = osBridge.ensure_jnienv (); + jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); + const char *mutf8 = env->GetStringUTFChars (name, nullptr); + char *ret = strdup (mutf8); + + env->ReleaseStringUTFChars (name, mutf8); + env->DeleteLocalRef (name); + + char *dot = strchr (ret, '.'); + while (dot != nullptr) { + *dot = '/'; + dot = strchr (dot + 1, '.'); + } + + return ret; +} + JNIEnv* get_jnienv (void) { diff --git a/src/monodroid/jni/timing.hh b/src/monodroid/jni/timing.hh new file mode 100644 index 00000000000..69bc871c8d1 --- /dev/null +++ b/src/monodroid/jni/timing.hh @@ -0,0 +1,156 @@ +#ifndef __TIMING_HH +#define __TIMING_HH + +#include +#include +#include +#include + +#ifdef ANDROID +#include +#endif + +#include "cppcompat.hh" +#include "logger.hh" + +namespace xamarin::android +{ + struct timing_point + { + time_t sec; + uint64_t ns; + + void mark (); + }; + + struct timing_period + { + timing_point start; + timing_point end; + + void mark_start () + { + start.mark (); + } + + void mark_end () + { + end.mark (); + } + }; + + struct timing_diff + { + static constexpr uint32_t ms_in_nsec = 1000000ULL; + + time_t sec; + uint32_t ms; + uint32_t ns; + + timing_diff (const timing_period &period); + }; + + struct managed_timing_sequence + { + timing_period period; + bool in_use; + bool dynamic; + }; + + // This class is intended to be used by the managed code. It can be used by the native code as + // well, but the overhead it has (out of necessity) might not be desirable in native code. +#define TIMING_FORMAT "; elapsed: %lis:%lu::%lu" + + class Timing + { + static constexpr char MESSAGE_FORMAT[] = "%s" TIMING_FORMAT; + + public: + static constexpr size_t DEFAULT_POOL_SIZE = 16; + + public: + explicit Timing (size_t initial_pool_size = DEFAULT_POOL_SIZE) noexcept + : sequence_pool_size (initial_pool_size) + { + sequence_pool = new managed_timing_sequence [initial_pool_size] (); + } + + ~Timing () noexcept + { + delete[] sequence_pool; + } + + static void info (timing_period const &period, const char *message) noexcept + { + timing_diff diff (period); + + log_info_nocheck (LOG_TIMING, MESSAGE_FORMAT, message == nullptr ? "" : message, diff.sec, diff.ms, diff.ns); + } + + static void warn (timing_period const &period, const char *message) noexcept + { + timing_diff diff (period); + + log_warn (LOG_TIMING, MESSAGE_FORMAT, message == nullptr ? "" : message, diff.sec, diff.ms, diff.ns); + } + + managed_timing_sequence* get_available_sequence () noexcept + { + std::lock_guard lock (sequence_lock); + + managed_timing_sequence *ret; + for (size_t i = 0; i < sequence_pool_size; i++) { + if (sequence_pool[i].in_use) { + continue; + } + + ret = &sequence_pool[i]; + ret->in_use = true; + ret->dynamic = false; + + return ret; + } + + ret = new managed_timing_sequence (); + ret->dynamic = true; + + return ret; + } + + void release_sequence (managed_timing_sequence *sequence) + { + if (sequence == nullptr) + return; + + std::lock_guard lock (sequence_lock); + if (sequence->dynamic) { + memset (sequence, 0, sizeof(*sequence)); + delete sequence; + return; + } + + sequence->in_use = false; + } + + private: + managed_timing_sequence *sequence_pool; + size_t sequence_pool_size; + std::mutex sequence_lock; + }; + + // This is a hack to avoid having to allocate memory when rendering messages that use additional + // format placeholders on the caller side. Memory allocation would be necessary since we append + // the standard timing suffix to every message printed. Using a variadic macro allows us to + // compose a call with all the elements present and make the composition compile-time. + // + // It could be done with template packs but that would result in extra code generated whenever a + // call with a different set of parameters would be made, plus the code to implement that would + // be a bit verbose and unwieldy, so we will stick to this simple method. +#define TIMING_DO_LOG(_level, _category_, ...) ::log_ ## _level ## _nocheck ((_category_), __VA_ARGS__) + +#define TIMING_LOG_INFO(__period__, __format__, ...) { \ + timing_diff diff ((__period__)); \ + TIMING_DO_LOG (info, LOG_TIMING, __format__ TIMING_FORMAT, __VA_ARGS__, diff.sec, diff.ms, diff.ns); \ + } +} +#endif // __TIMING_HH diff --git a/src/monodroid/jni/util.hh b/src/monodroid/jni/util.hh index d9d7ea82a48..da8c994a1f0 100644 --- a/src/monodroid/jni/util.hh +++ b/src/monodroid/jni/util.hh @@ -62,41 +62,6 @@ extern "C" { namespace xamarin::android { - struct timing_point - { - time_t sec; - uint64_t ns; - - void mark (); - }; - - struct timing_period - { - timing_point start; - timing_point end; - - void mark_start () - { - start.mark (); - } - - void mark_end () - { - end.mark (); - } - }; - - struct timing_diff - { - static constexpr uint32_t ms_in_nsec = 1000000ULL; - - time_t sec; - uint32_t ms; - uint32_t ns; - - timing_diff (const timing_period &period); - }; - class Util : public BasicUtilities { #if defined (ANDROID) || defined (LINUX) diff --git a/src/monodroid/jni/xamarin-app.h b/src/monodroid/jni/xamarin-app.h index b771b7b7506..1de8a893b5e 100644 --- a/src/monodroid/jni/xamarin-app.h +++ b/src/monodroid/jni/xamarin-app.h @@ -20,6 +20,8 @@ struct ApplicationConfig bool uses_mono_aot; bool uses_assembly_preload; bool is_a_bundled_app; + bool broken_exception_transitions; + uint32_t package_naming_policy; uint32_t environment_variable_count; uint32_t system_property_count; const char *android_package_name;