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..585cd421262 160000
--- a/external/Java.Interop
+++ b/external/Java.Interop
@@ -1 +1 @@
-Subproject commit 4f06201b598ac3816184ea7a0b71f540f6abe9d6
+Subproject commit 585cd421262e70816a404524c5f3ba7c9c929ab1
diff --git a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
index fa71749e460..e14e67740fe 100644
--- a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
+++ b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
@@ -36,15 +36,7 @@
-->
-
-
-
-
-
-
-
-
diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
index e6de9e23399..182a69695fc 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);
}
}
@@ -470,6 +477,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..42a3553adbf 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnv.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs
@@ -76,49 +76,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..5efac42f42b 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
@@ -35,7 +35,7 @@ internal struct JnienvInitializeArgs {
}
#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;
@@ -94,7 +94,7 @@ 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;
diff --git a/src/Mono.Android/Android.Runtime/JavaProxyThrowable.cs b/src/Mono.Android/Android.Runtime/JavaProxyThrowable.cs
index d221bf48054..defbbf9d568 100644
--- a/src/Mono.Android/Android.Runtime/JavaProxyThrowable.cs
+++ b/src/Mono.Android/Android.Runtime/JavaProxyThrowable.cs
@@ -116,6 +116,7 @@ public static JavaProxyThrowable Create (Exception innerException)
void TranslateStackTrace ()
{
+ Console.WriteLine ("# jonp: JavaProxyThrowable.TranslateStackTrace: InnerException={0} {1}", InnerException?.GetType(), InnerException);
// FIXME: https://github.com/xamarin/xamarin-android/issues/8724
// StackFrame.GetMethod() will return null under NativeAOT;
// However, you can still get useful information from StackFrame.ToString():
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..55a040f7131 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);
}
diff --git a/src/Mono.Android/Java.Lang/Object.cs b/src/Mono.Android/Java.Lang/Object.cs
index 9df5b5bbee9..d45c6d295d3 100644
--- a/src/Mono.Android/Java.Lang/Object.cs
+++ b/src/Mono.Android/Java.Lang/Object.cs
@@ -14,64 +14,31 @@
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)
+ var peerRef = PeerReference;
+ if (peerRef.IsValid) {
+ handle = peerRef.Handle;
+ ((IJavaPeerable) this).SetJniManagedPeerState (JniManagedPeerStates.Activatable);
+ if (peerRef.Type != JniObjectReferenceType.Invalid)
return;
transfer = JniHandleOwnership.DoNotTransfer;
}
@@ -92,31 +59,26 @@ internal void SetHandleOnDeserialized (StreamingContext context)
JNIEnv.FinishCreateInstance (Handle, "()V");
}
-#if JAVA_INTEROP
[EditorBrowsable (EditorBrowsableState.Never)]
- public int JniIdentityHashCode {
- get {return (int) key_handle;}
- }
+ public int JniIdentityHashCode => base.JniIdentityHashCode;
[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public JniObjectReference PeerReference {
- get {
- return new JniObjectReference (handle, (JniObjectReferenceType) handle_type);
- }
- }
+ public 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 +104,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;
- }
+ public new void UnregisterFromRuntime () => base.UnregisterFromRuntime ();
- void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
+ protected override void Dispose (bool disposing)
{
- 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);
- }
-
- 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..2d1b1b1edb6 100644
--- a/src/Mono.Android/Java.Lang/Throwable.cs
+++ b/src/Mono.Android/Java.Lang/Throwable.cs
@@ -9,37 +9,24 @@
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)
+ var peerRef = PeerReference;
+ if (peerRef.IsValid) {
+ ((IJavaPeerable) this).SetJniManagedPeerState (JniManagedPeerStates.Activatable);
+ handle = peerRef.Handle;
+ if (peerRef.Type != JniObjectReferenceType.Invalid)
return;
transfer = JniHandleOwnership.DoNotTransfer;
}
@@ -47,153 +34,45 @@ public Throwable (IntPtr handle, JniHandleOwnership transfer)
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;
+ var peerRef = PeerReference;
+ if (!peerRef.IsValid)
+ return IntPtr.Zero;
+ return peerRef.NewLocalRef ().Handle;
}
}
- string ManagedStackTraceAddendum {
- get {
- var javaStack = JavaStackTrace;
- if (string.IsNullOrEmpty (javaStack))
- return "";
- return Environment.NewLine +
- " --- End of managed " +
- GetType ().FullName +
- " stack trace ---" + Environment.NewLine +
- javaStack;
- }
- }
-
- 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 int JniIdentityHashCode => base.JniIdentityHashCode;
[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public JniObjectReference PeerReference {
- get {
- return new JniObjectReference (handle, (JniObjectReferenceType) handle_type);
- }
- }
+ public 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 +96,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 +109,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 +141,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 void UnregisterFromRuntime ()
- {
- JNIEnvInit.AndroidValueManager?.RemovePeer (this, key_handle);
- }
-
- void IJavaPeerable.Disposed ()
- {
- Dispose (disposing: true);
}
- void IJavaPeerable.Finalized ()
- {
- Dispose (disposing: false);
- }
+ public void UnregisterFromRuntime () => base.UnregisterFromRuntime ();
- 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 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/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}");
}
}
}