diff --git a/.gitmodules b/.gitmodules
index ea5f83ceb43..c734e652680 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,7 +13,7 @@
[submodule "external/Java.Interop"]
path = external/Java.Interop
url = https://github.com/dotnet/java-interop
- branch = main
+ branch = dev/jonp/jonp-overridable-Throwable-ctor-arg
[submodule "external/libunwind"]
path = external/libunwind
url = https://github.com/libunwind/libunwind.git
diff --git a/external/Java.Interop b/external/Java.Interop
index 4f06201b598..52e154a9e1a 160000
--- a/external/Java.Interop
+++ b/external/Java.Interop
@@ -1 +1 @@
-Subproject commit 4f06201b598ac3816184ea7a0b71f540f6abe9d6
+Subproject commit 52e154a9e1a34bd8f17c5e8ab5284d7f6c96c09b
diff --git a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
index fa71749e460..aa0a341e0bb 100644
--- a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
+++ b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
@@ -9,7 +9,6 @@
-
@@ -36,15 +35,7 @@
-->
-
-
-
-
-
-
-
-
diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
index e6de9e23399..abf30a6ef4b 100644
--- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
+++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
@@ -56,7 +56,7 @@ public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool f
{
if (!reference.IsValid)
return null;
- var peeked = JNIEnvInit.AndroidValueManager?.PeekPeer (reference);
+ var peeked = JNIEnvInit.ValueManager?.PeekPeer (reference);
var peekedExc = peeked as Exception;
if (peekedExc == null) {
var throwable = Java.Lang.Object.GetObject (reference.Handle, JniHandleOwnership.DoNotTransfer);
@@ -64,21 +64,28 @@ public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool f
return throwable;
}
JniObjectReference.Dispose (ref reference, options);
- var unwrapped = JNIEnvInit.AndroidValueManager?.UnboxException (peeked!);
+ var unwrapped = UnboxException (peeked!);
if (unwrapped != null) {
return unwrapped;
}
return peekedExc;
}
+ Exception? UnboxException (IJavaPeerable value)
+ {
+ if (JNIEnvInit.ValueManager is AndroidValueManager vm) {
+ return vm.UnboxException (value);
+ }
+ return null;
+ }
+
public override void RaisePendingException (Exception pendingException)
{
- var je = pendingException as JavaProxyThrowable;
+ var je = pendingException as JavaException;
if (je == null) {
je = JavaProxyThrowable.Create (pendingException);
}
- var r = new JniObjectReference (je.Handle);
- JniEnvironment.Exceptions.Throw (r);
+ JniEnvironment.Exceptions.Throw (je.PeerReference);
}
}
@@ -158,6 +165,14 @@ public override IntPtr ReleaseLocalReference (ref JniObjectReference value, ref
return r;
}
+ public override bool LogGlobalReferenceMessages => Logger.LogGlobalRef;
+ public override bool LogLocalReferenceMessages => Logger.LogLocalRef;
+
+ public override void WriteLocalReferenceLine (string format, params object?[] args)
+ {
+ RuntimeNativeMethods._monodroid_gref_log ("[LREF] " + string.Format (CultureInfo.InvariantCulture, format, args));
+ }
+
public override void WriteGlobalReferenceLine (string format, params object?[] args)
{
RuntimeNativeMethods._monodroid_gref_log (string.Format (CultureInfo.InvariantCulture, format, args));
@@ -470,6 +485,7 @@ static bool CallRegisterMethodByIndex (JniNativeMethodRegistrationArguments argu
}
}
+ [Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan) instead.")]
public override void RegisterNativeMembers (
JniType nativeClass,
[DynamicallyAccessedMembers (MethodsAndPrivateNested)]
diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs
index 9d6ba857379..26a4e3fd5cb 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnv.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs
@@ -52,7 +52,8 @@ internal static bool IsGCUserPeer (IntPtr value)
if (value == IntPtr.Zero)
return false;
- return IsInstanceOf (value, JNIEnvInit.grefIGCUserPeer_class);
+ return IsInstanceOf (value, JNIEnvInit.grefIGCUserPeer_class) ||
+ IsInstanceOf (value, JNIEnvInit.grefGCUserPeerable_class);
}
internal static bool ShouldWrapJavaException (Java.Lang.Throwable? t, [CallerMemberName] string? caller = null)
@@ -76,49 +77,6 @@ internal static bool ShouldWrapJavaException (Java.Lang.Throwable? t, [CallerMem
return wrap;
}
- [DllImport ("libc")]
- static extern int gettid ();
-
- internal static void Exit ()
- {
- /* Manually dispose surfaced objects and close the current JniEnvironment to
- * avoid ObjectDisposedException thrown on finalizer threads after shutdown
- */
- foreach (var surfacedObject in Java.Interop.Runtime.GetSurfacedObjects ()) {
- try {
- var obj = surfacedObject.Target as IDisposable;
- if (obj != null)
- obj.Dispose ();
- continue;
- } catch (Exception e) {
- RuntimeNativeMethods.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
- * fallback to manual deletion of the surfaced object.
- */
- var jobj = surfacedObject.Target as Java.Lang.Object;
- if (jobj != null)
- ManualJavaObjectDispose (jobj);
- }
- JniEnvironment.Runtime.Dispose ();
- }
-
- /* FIXME: This reproduces the minimal steps in Java.Lang.Object.Dispose
- * that needs to be executed so that we don't leak any GREF and prevent
- * code execution into an appdomain that we are disposing via a finalizer.
- * Ideally it should be done via another more generic mechanism, likely
- * from the Java.Interop.Runtime API.
- */
- static void ManualJavaObjectDispose (Java.Lang.Object obj)
- {
- var peer = obj.PeerReference;
- var handle = peer.Handle;
- var keyHandle = ((IJavaObjectEx)obj).KeyHandle;
- Java.Lang.Object.Dispose (obj, ref handle, keyHandle, (JObjectRefType)peer.Type);
- GC.SuppressFinalize (obj);
- }
-
internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPtr, IntPtr javaExceptionPtr)
{
if (!JNIEnvInit.PropagateExceptions)
diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
index c942c6c3f43..19ff11a0913 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
@@ -32,10 +32,11 @@ internal struct JnienvInitializeArgs {
public int jniAddNativeMethodRegistrationAttributePresent;
public bool jniRemappingInUse;
public bool marshalMethodsEnabled;
+ public IntPtr grefGCUserPeerable;
}
#pragma warning restore 0649
- internal static AndroidValueManager? AndroidValueManager;
+ internal static JniRuntime.JniValueManager? ValueManager;
internal static bool IsRunningOnDesktop;
internal static bool jniRemappingInUse;
internal static bool MarshalMethodsEnabled;
@@ -43,6 +44,7 @@ internal struct JnienvInitializeArgs {
internal static BoundExceptionType BoundExceptionType;
internal static int gref_gc_threshold;
internal static IntPtr grefIGCUserPeer_class;
+ internal static IntPtr grefGCUserPeerable_class;
internal static IntPtr java_class_loader;
internal static JniMethodInfo? mid_Class_forName;
@@ -94,11 +96,12 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
BoundExceptionType = (BoundExceptionType)args->ioExceptionType;
androidRuntime = new AndroidRuntime (args->env, args->javaVm, args->grefLoader, args->Loader_loadClass, args->jniAddNativeMethodRegistrationAttributePresent != 0);
- AndroidValueManager = (AndroidValueManager) androidRuntime.ValueManager;
+ ValueManager = androidRuntime.ValueManager;
IsRunningOnDesktop = args->isRunningOnDesktop == 1;
grefIGCUserPeer_class = args->grefIGCUserPeer;
+ grefGCUserPeerable_class = args->grefGCUserPeerable;
PropagateExceptions = args->brokenExceptionTransitions == 0;
diff --git a/src/Mono.Android/Java.Interop/IJavaObjectEx.cs b/src/Mono.Android/Java.Interop/IJavaObjectEx.cs
index 4e09670fc9c..e66229d1b9b 100644
--- a/src/Mono.Android/Java.Interop/IJavaObjectEx.cs
+++ b/src/Mono.Android/Java.Interop/IJavaObjectEx.cs
@@ -3,9 +3,6 @@
namespace Java.Interop {
interface IJavaObjectEx {
- IntPtr KeyHandle {get; set;}
- bool IsProxy {get; set;}
- bool NeedsActivation {get; set;}
IntPtr ToLocalJniHandle ();
}
}
diff --git a/src/Mono.Android/Java.Interop/Runtime.cs b/src/Mono.Android/Java.Interop/Runtime.cs
index ceb14ca9d87..8d69aedffa4 100644
--- a/src/Mono.Android/Java.Interop/Runtime.cs
+++ b/src/Mono.Android/Java.Interop/Runtime.cs
@@ -11,7 +11,7 @@ public static class Runtime {
[Obsolete ("Please use Java.Interop.JniEnvironment.Runtime.ValueManager.GetSurfacedPeers()")]
public static List GetSurfacedObjects ()
{
- var peers = JNIEnvInit.AndroidValueManager!.GetSurfacedPeers ();
+ var peers = JNIEnvInit.ValueManager!.GetSurfacedPeers ();
var r = new List (peers.Count);
foreach (var p in peers) {
if (p.SurfacedPeer.TryGetTarget (out var target))
diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs
index 04aa1f0ed5a..8b775aea7db 100644
--- a/src/Mono.Android/Java.Interop/TypeManager.cs
+++ b/src/Mono.Android/Java.Interop/TypeManager.cs
@@ -133,9 +133,10 @@ static Type[] GetParameterTypes (string? signature)
static void n_Activate (IntPtr jnienv, IntPtr jclass, IntPtr typename_ptr, IntPtr signature_ptr, IntPtr jobject, IntPtr parameters_ptr)
{
var o = Java.Lang.Object.PeekObject (jobject);
- var ex = o as IJavaObjectEx;
+ var ex = o as IJavaPeerable;
if (ex != null) {
- if (!ex.NeedsActivation && !ex.IsProxy)
+ var state = ex.JniManagedPeerState;
+ if (!state.HasFlag (JniManagedPeerStates.Activatable) && !state.HasFlag (JniManagedPeerStates.Replaceable))
return;
}
if (!ActivationEnabled) {
@@ -171,10 +172,8 @@ internal static void Activate (IntPtr jobject, ConstructorInfo cinfo, object? []
{
try {
var newobj = RuntimeHelpers.GetUninitializedObject (cinfo.DeclaringType!);
- if (newobj is Java.Lang.Object o) {
- o.handle = jobject;
- } else if (newobj is Java.Lang.Throwable throwable) {
- throwable.handle = jobject;
+ if (newobj is IJavaPeerable peer) {
+ peer.SetPeerReference (new JniObjectReference (jobject));
} else {
throw new InvalidOperationException ($"Unsupported type: '{newobj}'");
}
@@ -232,7 +231,7 @@ static Exception CreateJavaLocationException ()
return null;
}
- internal static IJavaPeerable CreateInstance (IntPtr handle, JniHandleOwnership transfer)
+ internal static IJavaPeerable? CreateInstance (IntPtr handle, JniHandleOwnership transfer)
{
return CreateInstance (handle, transfer, null);
}
@@ -320,7 +319,7 @@ internal static IJavaPeerable CreateInstance (IntPtr handle, JniHandleOwnership
try {
result = (IJavaPeerable) CreateProxy (type, handle, transfer);
if (Runtime.IsGCUserPeer (result.PeerReference.Handle)) {
- result.SetJniManagedPeerState (JniManagedPeerStates.Replaceable);
+ result.SetJniManagedPeerState (JniManagedPeerStates.Replaceable | JniManagedPeerStates.Activatable);
}
} catch (MissingMethodException e) {
var key_handle = JNIEnv.IdentityHash (handle);
@@ -353,7 +352,6 @@ internal static object CreateProxy (
JniObjectReferenceOptions o = JniObjectReferenceOptions.Copy;
var peer = (IJavaPeerable) c.Invoke (new object [] { r, o });
JNIEnv.DeleteRef (handle, transfer);
- peer.SetJniManagedPeerState (peer.JniManagedPeerState | JniManagedPeerStates.Replaceable);
return peer;
}
throw new MissingMethodException (
diff --git a/src/Mono.Android/Java.Lang/Object.cs b/src/Mono.Android/Java.Lang/Object.cs
index 9df5b5bbee9..fe6b49a8abf 100644
--- a/src/Mono.Android/Java.Lang/Object.cs
+++ b/src/Mono.Android/Java.Lang/Object.cs
@@ -14,68 +14,25 @@
namespace Java.Lang {
[Serializable]
- public partial class Object : IDisposable, IJavaObject, IJavaObjectEx
-#if JAVA_INTEROP
- , IJavaPeerable
-#endif // JAVA_INTEROP
+ public partial class Object : global::Java.Interop.JavaObject, IJavaObject, IJavaObjectEx
{
- [NonSerialized] IntPtr key_handle;
-#pragma warning disable CS0649, CS0169, CS0414 // Suppress fields are never used warnings, these fields are used directly by monodroid-glue.cc
- [NonSerialized] int refs_added;
-#pragma warning restore CS0649, CS0169, CS0414
- [NonSerialized] JObjectRefType handle_type;
- [NonSerialized] internal IntPtr handle;
- [NonSerialized] bool needsActivation;
- [NonSerialized] bool isProxy;
-
- IntPtr IJavaObjectEx.KeyHandle {
- get {return key_handle;}
- set {key_handle = value;}
- }
-
- bool IJavaObjectEx.IsProxy {
- get {return isProxy;}
- set {isProxy = value;}
- }
-
- bool IJavaObjectEx.NeedsActivation {
- get {return needsActivation;}
- set {needsActivation = true;}
- }
-
IntPtr IJavaObjectEx.ToLocalJniHandle ()
{
lock (this) {
- if (handle == IntPtr.Zero)
- return handle;
- return JNIEnv.NewLocalRef (handle);
+ var peerRef = PeerReference;
+ if (!peerRef.IsValid)
+ return IntPtr.Zero;
+ return peerRef.NewLocalRef ().Handle;
}
}
~Object ()
{
- // FIXME: need hash cleanup mechanism.
- // Finalization occurs after a test of java persistence. If the
- // handle still contains a java reference, we can't finalize the
- // object and should "resurrect" it.
- refs_added = 0;
- if (Environment.HasShutdownStarted) {
- return;
- }
- JniEnvironment.Runtime.ValueManager.FinalizePeer (this);
}
- public Object (IntPtr handle, JniHandleOwnership transfer)
+ public unsafe Object (IntPtr handle, JniHandleOwnership transfer)
+ : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
{
- // Check if handle was preset by our java activation mechanism
- if (this.handle != IntPtr.Zero) {
- needsActivation = true;
- handle = this.handle;
- if (handle_type != 0)
- return;
- transfer = JniHandleOwnership.DoNotTransfer;
- }
-
SetHandle (handle, transfer);
}
@@ -92,31 +49,27 @@ internal void SetHandleOnDeserialized (StreamingContext context)
JNIEnv.FinishCreateInstance (Handle, "()V");
}
-#if JAVA_INTEROP
[EditorBrowsable (EditorBrowsableState.Never)]
- public int JniIdentityHashCode {
- get {return (int) key_handle;}
- }
+ public new int JniIdentityHashCode => base.JniIdentityHashCode;
[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public JniObjectReference PeerReference {
- get {
- return new JniObjectReference (handle, (JniObjectReferenceType) handle_type);
- }
- }
+ public new JniObjectReference PeerReference => base.PeerReference;
[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public virtual JniPeerMembers JniPeerMembers {
+ public override JniPeerMembers JniPeerMembers {
get { return _members; }
}
-#endif // JAVA_INTEROP
[EditorBrowsable (EditorBrowsableState.Never)]
public IntPtr Handle {
get {
- return handle;
+ var peerRef = PeerReference;
+ if (!peerRef.IsValid) {
+ return IntPtr.Zero;
+ }
+ return peerRef.Handle;
}
}
@@ -142,115 +95,29 @@ internal System.Type GetThresholdType ()
return ThresholdType;
}
-#if JAVA_INTEROP
- JniManagedPeerStates IJavaPeerable.JniManagedPeerState {
- get {
- var e = (IJavaObjectEx) this;
- var s = JniManagedPeerStates.None;
- if (e.IsProxy)
- s |= JniManagedPeerStates.Replaceable;
- if (e.NeedsActivation)
- s |= JniManagedPeerStates.Activatable;
- return s;
- }
- }
-
- void IJavaPeerable.DisposeUnlessReferenced ()
- {
- var p = PeekObject (handle);
- if (p == null) {
- Dispose ();
- }
- }
-
[EditorBrowsable (EditorBrowsableState.Never)]
- public void UnregisterFromRuntime ()
- {
- JNIEnvInit.AndroidValueManager?.RemovePeer (this, key_handle);
- }
-
- void IJavaPeerable.Disposed ()
- {
- Dispose (disposing: true);
- }
-
- void IJavaPeerable.Finalized ()
- {
- Dispose (disposing: false);
- }
-
- void IJavaPeerable.SetJniIdentityHashCode (int value)
- {
- key_handle = (IntPtr) value;
- }
-
- void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
- {
- var e = (IJavaObjectEx) this;
- if ((value & JniManagedPeerStates.Replaceable) == JniManagedPeerStates.Replaceable)
- e.IsProxy = true;
- if ((value & JniManagedPeerStates.Activatable) == JniManagedPeerStates.Activatable)
- e.NeedsActivation = true;
- }
-
- void IJavaPeerable.SetPeerReference (JniObjectReference reference)
- {
- this.handle = reference.Handle;
- this.handle_type = (JObjectRefType) reference.Type;
- }
-#endif // JAVA_INTEROP
-
+ public new void UnregisterFromRuntime () => base.UnregisterFromRuntime ();
- public void Dispose ()
+ protected override void Dispose (bool disposing)
{
- JNIEnvInit.AndroidValueManager?.DisposePeer (this);
}
- protected virtual void Dispose (bool disposing)
- {
- }
-
- internal static void Dispose (IJavaPeerable instance, ref IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
- {
- if (handle == IntPtr.Zero)
- return;
-
- if (Logger.LogGlobalRef) {
- RuntimeNativeMethods._monodroid_gref_log (
- FormattableString.Invariant ($"Disposing handle 0x{handle:x}\n"));
- }
-
- JNIEnvInit.AndroidValueManager?.RemovePeer (instance, key_handle);
-
- switch (handle_type) {
- case JObjectRefType.Global:
- lock (instance) {
- JNIEnv.DeleteGlobalRef (handle);
- handle = IntPtr.Zero;
- }
- break;
- case JObjectRefType.WeakGlobal:
- lock (instance) {
- JNIEnv.DeleteWeakGlobalRef (handle);
- handle = IntPtr.Zero;
- }
- break;
- default:
- throw new InvalidOperationException ("Trying to dispose handle of type '" +
- handle_type + "' which is not supported.");
- }
- }
+ public new void Dispose () => base.Dispose ();
[EditorBrowsable (EditorBrowsableState.Never)]
protected void SetHandle (IntPtr value, JniHandleOwnership transfer)
{
- JNIEnvInit.AndroidValueManager?.AddPeer (this, value, transfer, out handle);
- handle_type = JObjectRefType.Global;
+ var reference = new JniObjectReference (value);
+ JNIEnvInit.ValueManager?.ConstructPeer (
+ this,
+ ref reference,
+ value == IntPtr.Zero ? JniObjectReferenceOptions.None : JniObjectReferenceOptions.Copy);
+ JNIEnv.DeleteRef (value, transfer);
}
internal static IJavaPeerable? PeekObject (IntPtr handle, Type? requiredType = null)
{
- var peeked = JNIEnvInit.AndroidValueManager?.PeekPeer (new JniObjectReference (handle));
+ var peeked = JNIEnvInit.ValueManager?.PeekPeer (new JniObjectReference (handle));
if (peeked == null)
return null;
if (requiredType != null && !requiredType.IsAssignableFrom (peeked.GetType ()))
diff --git a/src/Mono.Android/Java.Lang/Throwable.cs b/src/Mono.Android/Java.Lang/Throwable.cs
index 498335e5d8e..a6dcdb4422f 100644
--- a/src/Mono.Android/Java.Lang/Throwable.cs
+++ b/src/Mono.Android/Java.Lang/Throwable.cs
@@ -9,191 +9,59 @@
namespace Java.Lang {
- public partial class Throwable : global::System.Exception, IJavaObject, IDisposable, IJavaObjectEx
-#if JAVA_INTEROP
- , IJavaPeerable
-#endif // JAVA_INTEROP
+ public partial class Throwable : JavaException, IJavaObject, IDisposable, IJavaObjectEx
{
-
protected bool is_generated;
- internal IntPtr handle;
-
- IntPtr key_handle;
- JObjectRefType handle_type;
-#pragma warning disable CS0649, CS0169, CS0414 // Suppress fields are never used warnings, these fields are used directly by monodroid-glue.cc
- int refs_added;
-#pragma warning restore CS0649, CS0169, CS0414
-
- bool isProxy;
- bool needsActivation;
- string? nativeStack;
-
- public Throwable (IntPtr handle, JniHandleOwnership transfer)
- : base (_GetMessage (handle), _GetInnerException (handle))
+ public unsafe Throwable (IntPtr handle, JniHandleOwnership transfer)
+ : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None, new JniObjectReference (handle))
{
if (GetType () == typeof (Throwable))
is_generated = true;
- // Check if handle was preset by our java activation mechanism
- if (this.handle != IntPtr.Zero) {
- needsActivation = true;
- handle = this.handle;
- if (handle_type != 0)
- return;
- transfer = JniHandleOwnership.DoNotTransfer;
- }
-
SetHandle (handle, transfer);
}
-#if JAVA_INTEROP
- static JniMethodInfo? Throwable_getMessage;
-#endif
-
- static string? _GetMessage (IntPtr handle)
- {
- if (handle == IntPtr.Zero)
- return null;
-
- IntPtr value;
-#if JAVA_INTEROP
- const string __id = "getMessage.()Ljava/lang/String;";
- if (Throwable_getMessage == null) {
- Throwable_getMessage = _members.InstanceMethods.GetMethodInfo (__id);
- }
- value = JniEnvironment.InstanceMethods.CallObjectMethod (new JniObjectReference (handle), Throwable_getMessage).Handle;
-#else // !JAVA_INTEROP
- if (id_getMessage == IntPtr.Zero)
- id_getMessage = JNIEnv.GetMethodID (class_ref, "getMessage", "()Ljava/lang/String;");
- value = JNIEnv.CallObjectMethod (handle, id_getMessage);
-#endif // !JAVA_INTEROP
-
- return JNIEnv.GetString (value, JniHandleOwnership.TransferLocalRef);
- }
-
-#if JAVA_INTEROP
- static JniMethodInfo? Throwable_getCause;
-#endif
-
- static global::System.Exception? _GetInnerException (IntPtr handle)
- {
- if (handle == IntPtr.Zero)
- return null;
-
- IntPtr value;
-#if JAVA_INTEROP
- const string __id = "getCause.()Ljava/lang/Throwable;";
- if (Throwable_getCause == null) {
- Throwable_getCause = _members.InstanceMethods.GetMethodInfo (__id);
- }
- value = JniEnvironment.InstanceMethods.CallObjectMethod (new JniObjectReference (handle), Throwable_getCause).Handle;
-#else // !JAVA_INTEROP
- if (id_getCause == IntPtr.Zero)
- id_getCause = JNIEnv.GetMethodID (class_ref, "getCause", "()Ljava/lang/Throwable;");
-
- value = JNIEnv.CallObjectMethod (handle, id_getCause);
-#endif // !JAVA_INTEROP
-
- var cause = global::Java.Lang.Object.GetObject (
- value,
- JniHandleOwnership.TransferLocalRef);
-
- var proxy = cause as JavaProxyThrowable;
- if (proxy != null)
- return proxy.InnerException;
-
- return cause;
- }
-
- IntPtr IJavaObjectEx.KeyHandle {
- get {return key_handle;}
- set {key_handle = value;}
- }
-
- bool IJavaObjectEx.IsProxy {
- get {return isProxy;}
- set {isProxy = value;}
- }
-
- bool IJavaObjectEx.NeedsActivation {
- get {return needsActivation;}
- set {needsActivation = true;}
- }
-
IntPtr IJavaObjectEx.ToLocalJniHandle ()
{
lock (this) {
- if (handle == IntPtr.Zero)
- return handle;
- return JNIEnv.NewLocalRef (handle);
- }
- }
-
- public override string StackTrace {
- get {
- return base.StackTrace + ManagedStackTraceAddendum;
- }
- }
-
- string ManagedStackTraceAddendum {
- get {
- var javaStack = JavaStackTrace;
- if (string.IsNullOrEmpty (javaStack))
- return "";
- return Environment.NewLine +
- " --- End of managed " +
- GetType ().FullName +
- " stack trace ---" + Environment.NewLine +
- javaStack;
+ var peerRef = PeerReference;
+ if (!peerRef.IsValid)
+ return IntPtr.Zero;
+ return peerRef.NewLocalRef ().Handle;
}
}
- string? JavaStackTrace {
- get {
- if (!string.IsNullOrEmpty (nativeStack))
- return nativeStack;
-
- if (handle == IntPtr.Zero)
- return null;
-
- using (var nativeStackWriter = new Java.IO.StringWriter ())
- using (var nativeStackPw = new Java.IO.PrintWriter (nativeStackWriter)) {
- PrintStackTrace (nativeStackPw);
- nativeStack = nativeStackWriter.ToString ();
- }
- return nativeStack;
- }
- }
+ public override string StackTrace => base.StackTrace;
public override string ToString ()
{
- return base.ToString () + ManagedStackTraceAddendum;
+ return base.ToString ();
}
-#if JAVA_INTEROP
[EditorBrowsable (EditorBrowsableState.Never)]
- public int JniIdentityHashCode {
- get {return (int) key_handle;}
- }
+ public new int JniIdentityHashCode => base.JniIdentityHashCode;
[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public JniObjectReference PeerReference {
- get {
- return new JniObjectReference (handle, (JniObjectReferenceType) handle_type);
- }
- }
+ public new JniObjectReference PeerReference => base.PeerReference;
[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public virtual JniPeerMembers JniPeerMembers {
+ public override JniPeerMembers JniPeerMembers {
get { return _members; }
}
-#endif // JAVA_INTEROP
[EditorBrowsable (EditorBrowsableState.Never)]
- public IntPtr Handle { get { return handle; } }
+ public IntPtr Handle {
+ get {
+ var peerRef = PeerReference;
+ if (!peerRef.IsValid) {
+ return IntPtr.Zero;
+ }
+ return peerRef.Handle;
+ }
+ }
[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
@@ -217,22 +85,12 @@ internal System.Type GetThresholdType ()
return ThresholdType;
}
-#if !JAVA_INTEROP
- static IntPtr id_getClass;
-#endif // !JAVA_INTEROP
-
public unsafe Java.Lang.Class? Class {
[Register ("getClass", "()Ljava/lang/Class;", "GetGetClassHandler")]
get {
IntPtr value;
-#if JAVA_INTEROP
const string __id = "getClass.()Ljava/lang/Class;";
value = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null).Handle;
-#else // !JAVA_INTEROP
- if (id_getClass == IntPtr.Zero)
- id_getClass = JNIEnv.GetMethodID (class_ref, "getClass", "()Ljava/lang/Class;");
- value = JNIEnv.CallObjectMethod (Handle, id_getClass);
-#endif // !JAVA_INTEROP
return global::Java.Lang.Object.GetObject (value, JniHandleOwnership.TransferLocalRef);
}
}
@@ -240,8 +98,15 @@ public unsafe Java.Lang.Class? Class {
[EditorBrowsable (EditorBrowsableState.Never)]
protected void SetHandle (IntPtr value, JniHandleOwnership transfer)
{
- JNIEnvInit.AndroidValueManager?.AddPeer (this, value, transfer, out handle);
- handle_type = JObjectRefType.Global;
+ var reference = new JniObjectReference (value);
+
+ Construct (
+ ref reference,
+ value == IntPtr.Zero ? JniObjectReferenceOptions.None : JniObjectReferenceOptions.Copy);
+ if (value != IntPtr.Zero) {
+ SetJavaStackTrace (new JniObjectReference (value));
+ }
+ JNIEnv.DeleteRef (value, transfer);
}
public static Throwable FromException (System.Exception e)
@@ -265,76 +130,13 @@ public static System.Exception ToException (Throwable e)
~Throwable ()
{
- refs_added = 0;
- if (Environment.HasShutdownStarted) {
- return;
- }
- JniEnvironment.Runtime.ValueManager.FinalizePeer (this);
- }
-
-#if JAVA_INTEROP
- JniManagedPeerStates IJavaPeerable.JniManagedPeerState {
- get {
- var e = (IJavaObjectEx) this;
- var s = JniManagedPeerStates.None;
- if (e.IsProxy)
- s |= JniManagedPeerStates.Replaceable;
- if (e.NeedsActivation)
- s |= JniManagedPeerStates.Activatable;
- return s;
- }
}
- void IJavaPeerable.DisposeUnlessReferenced ()
- {
- var p = Object.PeekObject (handle);
- if (p == null) {
- Dispose ();
- }
- }
+ public new void UnregisterFromRuntime () => base.UnregisterFromRuntime ();
- public void UnregisterFromRuntime ()
- {
- JNIEnvInit.AndroidValueManager?.RemovePeer (this, key_handle);
- }
-
- void IJavaPeerable.Disposed ()
- {
- Dispose (disposing: true);
- }
-
- void IJavaPeerable.Finalized ()
- {
- Dispose (disposing: false);
- }
-
- void IJavaPeerable.SetJniIdentityHashCode (int value)
- {
- key_handle = (IntPtr) value;
- }
-
- void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
- {
- var e = (IJavaObjectEx) this;
- if ((value & JniManagedPeerStates.Replaceable) == JniManagedPeerStates.Replaceable)
- e.IsProxy = true;
- if ((value & JniManagedPeerStates.Activatable) == JniManagedPeerStates.Activatable)
- e.NeedsActivation = true;
- }
-
- void IJavaPeerable.SetPeerReference (JniObjectReference reference)
- {
- this.handle = reference.Handle;
- this.handle_type = (JObjectRefType) reference.Type;
- }
-#endif // JAVA_INTEROP
-
- public void Dispose ()
- {
- JNIEnvInit.AndroidValueManager?.DisposePeer (this);
- }
+ public new void Dispose () => base.Dispose ();
- protected virtual void Dispose (bool disposing)
+ protected override void Dispose (bool disposing)
{
}
}
diff --git a/src/Mono.Android/PublicAPI/API-35/PublicAPI.Shipped.txt b/src/Mono.Android/PublicAPI/API-35/PublicAPI.Shipped.txt
index a015c8c4a8f..d71147178cd 100644
--- a/src/Mono.Android/PublicAPI/API-35/PublicAPI.Shipped.txt
+++ b/src/Mono.Android/PublicAPI/API-35/PublicAPI.Shipped.txt
@@ -125925,10 +125925,10 @@ virtual Java.Lang.NoSuchMethodException.Clause.get -> Java.Lang.Throwable?
virtual Java.Lang.Number.ByteValue() -> sbyte
virtual Java.Lang.Number.ShortValue() -> short
virtual Java.Lang.Object.Clone() -> Java.Lang.Object!
-virtual Java.Lang.Object.Dispose(bool disposing) -> void
+override Java.Lang.Object.Dispose(bool disposing) -> void
virtual Java.Lang.Object.Equals(Java.Lang.Object? obj) -> bool
virtual Java.Lang.Object.JavaFinalize() -> void
-virtual Java.Lang.Object.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
+override Java.Lang.Object.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
virtual Java.Lang.Object.ThresholdClass.get -> nint
virtual Java.Lang.Object.ThresholdType.get -> System.Type!
virtual Java.Lang.Package.GetAnnotation(Java.Lang.Class? annotationClass) -> Java.Lang.Object?
@@ -126069,11 +126069,11 @@ virtual Java.Lang.ThreadLocal.InitialValue() -> Java.Lang.Object?
virtual Java.Lang.ThreadLocal.Remove() -> void
virtual Java.Lang.ThreadLocal.Set(Java.Lang.Object? value) -> void
virtual Java.Lang.Throwable.Cause.get -> Java.Lang.Throwable?
-virtual Java.Lang.Throwable.Dispose(bool disposing) -> void
+override Java.Lang.Throwable.Dispose(bool disposing) -> void
virtual Java.Lang.Throwable.FillInStackTrace() -> Java.Lang.Throwable!
virtual Java.Lang.Throwable.GetStackTrace() -> Java.Lang.StackTraceElement![]!
virtual Java.Lang.Throwable.InitCause(Java.Lang.Throwable? cause) -> Java.Lang.Throwable!
-virtual Java.Lang.Throwable.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
+override Java.Lang.Throwable.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
virtual Java.Lang.Throwable.LocalizedMessage.get -> string?
virtual Java.Lang.Throwable.Message.get -> string?
virtual Java.Lang.Throwable.PrintStackTrace() -> void
diff --git a/src/Mono.Android/PublicAPI/API-36/PublicAPI.Shipped.txt b/src/Mono.Android/PublicAPI/API-36/PublicAPI.Shipped.txt
index f53c05485ad..fd95b1c938b 100644
--- a/src/Mono.Android/PublicAPI/API-36/PublicAPI.Shipped.txt
+++ b/src/Mono.Android/PublicAPI/API-36/PublicAPI.Shipped.txt
@@ -125925,10 +125925,10 @@ virtual Java.Lang.NoSuchMethodException.Clause.get -> Java.Lang.Throwable?
virtual Java.Lang.Number.ByteValue() -> sbyte
virtual Java.Lang.Number.ShortValue() -> short
virtual Java.Lang.Object.Clone() -> Java.Lang.Object!
-virtual Java.Lang.Object.Dispose(bool disposing) -> void
+override Java.Lang.Object.Dispose(bool disposing) -> void
virtual Java.Lang.Object.Equals(Java.Lang.Object? obj) -> bool
virtual Java.Lang.Object.JavaFinalize() -> void
-virtual Java.Lang.Object.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
+override Java.Lang.Object.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
virtual Java.Lang.Object.ThresholdClass.get -> nint
virtual Java.Lang.Object.ThresholdType.get -> System.Type!
virtual Java.Lang.Package.GetAnnotation(Java.Lang.Class? annotationClass) -> Java.Lang.Object?
@@ -126069,11 +126069,11 @@ virtual Java.Lang.ThreadLocal.InitialValue() -> Java.Lang.Object?
virtual Java.Lang.ThreadLocal.Remove() -> void
virtual Java.Lang.ThreadLocal.Set(Java.Lang.Object? value) -> void
virtual Java.Lang.Throwable.Cause.get -> Java.Lang.Throwable?
-virtual Java.Lang.Throwable.Dispose(bool disposing) -> void
+override Java.Lang.Throwable.Dispose(bool disposing) -> void
virtual Java.Lang.Throwable.FillInStackTrace() -> Java.Lang.Throwable!
virtual Java.Lang.Throwable.GetStackTrace() -> Java.Lang.StackTraceElement![]!
virtual Java.Lang.Throwable.InitCause(Java.Lang.Throwable? cause) -> Java.Lang.Throwable!
-virtual Java.Lang.Throwable.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
+override Java.Lang.Throwable.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
virtual Java.Lang.Throwable.LocalizedMessage.get -> string?
virtual Java.Lang.Throwable.Message.get -> string?
virtual Java.Lang.Throwable.PrintStackTrace() -> void
diff --git a/src/java-runtime/java/mono/android/Runtime.java b/src/java-runtime/java/mono/android/Runtime.java
index aacc0e9fd78..8ad03b1a2c5 100644
--- a/src/java-runtime/java/mono/android/Runtime.java
+++ b/src/java-runtime/java/mono/android/Runtime.java
@@ -9,6 +9,7 @@ public class Runtime {
static java.lang.Class java_util_TimeZone = java.util.TimeZone.class;
static java.lang.Class mono_android_IGCUserPeer = mono.android.IGCUserPeer.class;
static java.lang.Class mono_android_GCUserPeer = mono.android.GCUserPeer.class;
+ static java.lang.Class net_dot_jni_GCUserPeerable = net.dot.jni.GCUserPeerable.class;
static {
Thread.setDefaultUncaughtExceptionHandler (new XamarinUncaughtExceptionHandler (Thread.getDefaultUncaughtExceptionHandler ()));
diff --git a/src/native/monodroid/monodroid-glue-designer.cc b/src/native/monodroid/monodroid-glue-designer.cc
deleted file mode 100644
index 8e8d6ab4cba..00000000000
--- a/src/native/monodroid/monodroid-glue-designer.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-//
-// Android designer support code, not used on devices
-//
-#include "globals.hh"
-#include "mono_android_Runtime.h"
-#include "monodroid-glue-internal.hh"
-
-using namespace xamarin::android::internal;
-
-// DO NOT USE ON NORMAL X.A
-// This function only works with the custom TypeManager embedded with the designer process.
-force_inline static void
-reinitialize_android_runtime_type_manager (JNIEnv *env)
-{
- jclass typeManager = env->FindClass ("mono/android/TypeManager");
- env->UnregisterNatives (typeManager);
-
- jmethodID resetRegistration = env->GetStaticMethodID (typeManager, "resetRegistration", "()V");
- env->CallStaticVoidMethod (typeManager, resetRegistration);
-
- env->DeleteLocalRef (typeManager);
-}
-
-inline void
-MonodroidRuntime::shutdown_android_runtime (MonoDomain *domain)
-{
- MonoClass *runtime = get_android_runtime_class (domain);
- MonoMethod *method = mono_class_get_method_from_name (runtime, "Exit", 0);
-
- utils.monodroid_runtime_invoke (domain, method, nullptr, nullptr, nullptr);
-}
-
-inline jint
-MonodroidRuntime::Java_mono_android_Runtime_createNewContextWithData (JNIEnv *env, jclass klass, jobjectArray runtimeApksJava, jobjectArray assembliesJava,
- jobjectArray assembliesBytes, jobjectArray assembliesPaths, jobject loader, jboolean force_preload_assemblies)
-{
- log_info (LOG_DEFAULT, "CREATING NEW CONTEXT");
- reinitialize_android_runtime_type_manager (env);
- MonoDomain *root_domain = mono_get_root_domain ();
- mono_jit_thread_attach (root_domain);
-
- jstring_array_wrapper runtimeApks (env, runtimeApksJava);
- jstring_array_wrapper assemblies (env, assembliesJava);
- jstring_array_wrapper assembliePaths (env, assembliesPaths);
- MonoDomain *domain = create_and_initialize_domain (env, klass, runtimeApks, assemblies, assembliesBytes, assembliePaths, loader, /*is_root_domain:*/ false, force_preload_assemblies, /* have_split_apks */ false);
- mono_domain_set (domain, FALSE);
- int domain_id = mono_domain_get_id (domain);
- current_context_id = domain_id;
- log_info (LOG_DEFAULT, "Created new context with id %d\n", domain_id);
- return domain_id;
-}
-
-inline void
-MonodroidRuntime::Java_mono_android_Runtime_switchToContext (JNIEnv *env, jint contextID)
-{
- log_info (LOG_DEFAULT, "SWITCHING CONTEXT");
- MonoDomain *domain = mono_domain_get_by_id ((int)contextID);
- if (current_context_id != (int)contextID) {
- mono_domain_set (domain, TRUE);
- // Reinitialize TypeManager so that its JNI handle goes into the right domain
- reinitialize_android_runtime_type_manager (env);
- }
- current_context_id = (int)contextID;
-}
-
-inline void
-MonodroidRuntime::Java_mono_android_Runtime_destroyContexts (JNIEnv *env, jintArray array)
-{
- MonoDomain *root_domain = mono_get_root_domain ();
- mono_jit_thread_attach (root_domain);
- current_context_id = -1;
-
- jint *contextIDs = env->GetIntArrayElements (array, nullptr);
- jsize count = env->GetArrayLength (array);
-
- log_info (LOG_DEFAULT, "Cleaning %d domains", count);
-
- for (jsize i = 0; i < count; i++) {
- int domain_id = contextIDs[i];
- MonoDomain *domain = mono_domain_get_by_id (domain_id);
-
- if (domain == nullptr)
- continue;
- log_info (LOG_DEFAULT, "Shutting down domain `%d'", contextIDs[i]);
- shutdown_android_runtime (domain);
- osBridge.remove_monodroid_domain (domain);
- designerAssemblies.clear_for_domain (domain);
- }
- osBridge.on_destroy_contexts ();
- for (jsize i = 0; i < count; i++) {
- int domain_id = contextIDs[i];
- MonoDomain *domain = mono_domain_get_by_id (domain_id);
-
- if (domain == nullptr)
- continue;
- log_info (LOG_DEFAULT, "Unloading domain `%d'", contextIDs[i]);
- mono_domain_unload (domain);
- }
- env->ReleaseIntArrayElements (array, contextIDs, JNI_ABORT);
-
- reinitialize_android_runtime_type_manager (env);
-
- log_info (LOG_DEFAULT, "All domain cleaned up");
-}
-
-JNIEXPORT jint
-JNICALL Java_mono_android_Runtime_createNewContextWithData (JNIEnv *env, jclass klass, jobjectArray runtimeApksJava, jobjectArray assembliesJava, jobjectArray assembliesBytes, jobjectArray assembliesPaths, jobject loader, jboolean force_preload_assemblies)
-{
- return monodroidRuntime.Java_mono_android_Runtime_createNewContextWithData (
- env,
- klass,
- runtimeApksJava,
- assembliesJava,
- assembliesBytes,
- assembliesPaths,
- loader,
- force_preload_assemblies
- );
-}
-
-/* !DO NOT REMOVE! Used by older versions of the Android Designer (pre-16.4) */
-JNIEXPORT jint
-JNICALL Java_mono_android_Runtime_createNewContext (JNIEnv *env, jclass klass, jobjectArray runtimeApksJava, jobjectArray assembliesJava, jobject loader)
-{
- return monodroidRuntime.Java_mono_android_Runtime_createNewContextWithData (
- env,
- klass,
- runtimeApksJava,
- assembliesJava,
- nullptr, // assembliesBytes
- nullptr, // assembliesPaths
- loader,
- false // force_preload_assemblies
- );
-}
-
-JNIEXPORT void
-JNICALL Java_mono_android_Runtime_switchToContext (JNIEnv *env, [[maybe_unused]] jclass klass, jint contextID)
-{
- monodroidRuntime.Java_mono_android_Runtime_switchToContext (env, contextID);
-}
-
-JNIEXPORT void
-JNICALL Java_mono_android_Runtime_destroyContexts (JNIEnv *env, [[maybe_unused]] jclass klass, jintArray array)
-{
- monodroidRuntime.Java_mono_android_Runtime_destroyContexts (env, array);
-}
diff --git a/src/native/monodroid/monodroid-glue-internal.hh b/src/native/monodroid/monodroid-glue-internal.hh
index da7f9f6be2c..c32882702bb 100644
--- a/src/native/monodroid/monodroid-glue-internal.hh
+++ b/src/native/monodroid/monodroid-glue-internal.hh
@@ -101,6 +101,7 @@ namespace xamarin::android::internal
int jniAddNativeMethodRegistrationAttributePresent;
bool jniRemappingInUse;
bool marshalMethodsEnabled;
+ jobject grefGCUserPeerable;
};
using jnienv_initialize_fn = void (*) (JnienvInitializeArgs*);
diff --git a/src/native/monodroid/monodroid-glue.cc b/src/native/monodroid/monodroid-glue.cc
index 7a28622554f..94e4944616c 100644
--- a/src/native/monodroid/monodroid-glue.cc
+++ b/src/native/monodroid/monodroid-glue.cc
@@ -930,6 +930,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec
init.grefLoader = env->NewGlobalRef (loader);
init.grefIGCUserPeer = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer", true);
+ init.grefGCUserPeerable = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "net_dot_jni_GCUserPeerable", true);
osBridge.initialize_on_runtime_init (env, runtimeClass);
diff --git a/src/native/monodroid/osbridge.cc b/src/native/monodroid/osbridge.cc
index 4d03b3600bb..919506d3fda 100644
--- a/src/native/monodroid/osbridge.cc
+++ b/src/native/monodroid/osbridge.cc
@@ -23,8 +23,6 @@ using namespace xamarin::android;
using namespace xamarin::android::internal;
const OSBridge::MonoJavaGCBridgeType OSBridge::mono_xa_gc_bridge_types[] = {
- { "Java.Lang", "Object" },
- { "Java.Lang", "Throwable" },
};
const OSBridge::MonoJavaGCBridgeType OSBridge::mono_ji_gc_bridge_types[] = {
diff --git a/tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs b/tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs
index a1efbb26591..420544ed116 100644
--- a/tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs
+++ b/tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs
@@ -287,6 +287,8 @@ public void ActivatedDirectThrowableSubclassesShouldBeRegistered ()
{
if (Build.VERSION.SdkInt <= BuildVersionCodes.GingerbreadMr1)
Assert.Ignore ("Skipping test due to Bug #34141");
+
+ Console.Error.WriteLine ($"# jonp: BEGIN ActivatedDirectThrowableSubclassesShouldBeRegistered!!!");
using (var ThrowableActivatedFromJava_class = Java.Lang.Class.FromType (typeof (ThrowableActivatedFromJava))) {
var ThrowableActivatedFromJava_init = JNIEnv.GetMethodID (ThrowableActivatedFromJava_class.Handle, "", "()V");
@@ -302,6 +304,7 @@ public void ActivatedDirectThrowableSubclassesShouldBeRegistered ()
Assert.IsTrue (v.Constructed);
v.Dispose ();
}
+ Console.Error.WriteLine ($"# jonp: END ActivatedDirectThrowableSubclassesShouldBeRegistered!!!");
}
[Test]
diff --git a/tests/Mono.Android-Tests/System/ExceptionTest.cs b/tests/Mono.Android-Tests/System/ExceptionTest.cs
index a1511e393d2..017308edf7c 100644
--- a/tests/Mono.Android-Tests/System/ExceptionTest.cs
+++ b/tests/Mono.Android-Tests/System/ExceptionTest.cs
@@ -43,6 +43,9 @@ public void InnerExceptionIsSet ()
using var source = new Java.Lang.Throwable ("detailMessage", proxy);
using var alias = new Java.Lang.Throwable (source.Handle, JniHandleOwnership.DoNotTransfer);
+ Console.Error.WriteLine ("# jonp: InnerExceptionIsSet: ex={0}", ex);
+ Console.Error.WriteLine ("# jonp: InnerExceptionIsSet: proxy={0}", proxy);
+
CompareStackTraces (ex, proxy);
Assert.AreEqual ("detailMessage", alias.Message);
Assert.AreSame (ex, alias.InnerException);
@@ -51,7 +54,7 @@ public void InnerExceptionIsSet ()
[RequiresUnreferencedCode ("Tests trimming unsafe features")]
void CompareStackTraces (Exception ex, Java.Lang.Throwable throwable)
{
- var managedTrace = new StackTrace (ex);
+ var managedTrace = new StackTrace (ex, fNeedFileInfo: true);
StackFrame[] managedFrames = managedTrace.GetFrames ();
Java.Lang.StackTraceElement[] javaFrames = throwable.GetStackTrace ();
@@ -68,15 +71,21 @@ void CompareStackTraces (Exception ex, Java.Lang.Throwable throwable)
managedLine = mf.HasNativeImage () ? -2 : -1;
}
+ Console.WriteLine ("# jonp: CompareStackTraces: managedFrame[{0}]: {1}", i, mf);
+ Console.WriteLine ("# jonp: CompareStackTraces: javaFrame[{0}]: {1}", i, jf);
if (managedLine > 0) {
Assert.AreEqual (mf.GetMethod ()?.Name, jf.MethodName, $"Frame {i}: method names differ");
} else {
string managedMethodName = mf.GetMethod ()?.Name ?? String.Empty;
- Assert.IsTrue (jf.MethodName.StartsWith ($"{managedMethodName} + 0x"), $"Frame {i}: method name should start with: '{managedMethodName} + 0x'");
+ Assert.IsTrue (jf.MethodName.StartsWith ($"{managedMethodName} + 0x"),
+ $"Frame {i}: method name should start with: '{managedMethodName} + 0x'; was `{jf.MethodName}`; ");
}
- Assert.AreEqual (mf.GetMethod ()?.DeclaringType.FullName, jf.ClassName, $"Frame {i}: class names differ");
- Assert.AreEqual (mf.GetFileName (), jf.FileName, $"Frame {i}: file names differ");
- Assert.AreEqual (managedLine, jf.LineNumber, $"Frame {i}: line numbers differ");
+ Assert.AreEqual (mf.GetMethod ()?.DeclaringType.FullName, jf.ClassName,
+ $"Frame {i}: class names differ: `{mf.GetMethod ()?.DeclaringType.FullName}` != `{jf.ClassName}`");
+ Assert.AreEqual (mf.GetFileName (), jf.FileName,
+ $"Frame {i}: file names differ: `{mf.GetFileName ()}` != `{jf.FileName}`");
+ Assert.AreEqual (managedLine, jf.LineNumber,
+ $"Frame {i}: line numbers differ: {managedLine} != {jf.LineNumber}");
}
}
}