diff --git a/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs index 340078864e8..5fed268de2f 100644 --- a/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs +++ b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs @@ -43,7 +43,7 @@ static void init (IntPtr jnienv, IntPtr klass, IntPtr classLoader) EnvironmentPointer = jnienv, ClassLoader = new JniObjectReference (classLoader), TypeManager = typeManager, - ValueManager = new ManagedValueManager (), + ValueManager = new SimpleValueManager (), UseMarshalMemberBuilder = false, JniGlobalReferenceLogWriter = settings.GrefLog, JniLocalReferenceLogWriter = settings.LrefLog, diff --git a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs index c660cbc325b..ed4068094f1 100644 --- a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs +++ b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs @@ -61,7 +61,7 @@ static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder) builder.TypeManager ??= new ManagedTypeManager (); #endif // NET - builder.ValueManager ??= new ManagedValueManager (); + builder.ValueManager ??= new SimpleValueManager (); builder.ObjectReferenceManager ??= new ManagedObjectReferenceManager (builder.JniGlobalReferenceLogWriter, builder.JniLocalReferenceLogWriter); if (builder.InvocationPointer != IntPtr.Zero || builder.EnvironmentPointer != IntPtr.Zero) diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs index 3f6d8f86cf2..f6a1ee4e3c3 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs @@ -58,7 +58,7 @@ public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool f { if (!reference.IsValid) return null; - var peeked = JNIEnvInit.ValueManager?.PeekPeer (reference); + var peeked = JniEnvironment.Runtime.ValueManager.PeekPeer (reference); var peekedExc = peeked as Exception; if (peekedExc == null) { var throwable = Java.Lang.Object.GetObject (reference.Handle, JniHandleOwnership.DoNotTransfer); @@ -66,7 +66,7 @@ public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool f return throwable; } JniObjectReference.Dispose (ref reference, options); - var unwrapped = JNIEnvInit.ValueManager?.PeekValue (peeked!.PeerReference) as Exception; + var unwrapped = JniEnvironment.Runtime.ValueManager.PeekValue (peeked!.PeerReference) as Exception; if (unwrapped != null) { return unwrapped; } diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index f2aa7961b82..305d44081f6 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -118,7 +118,7 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt public static void WaitForBridgeProcessing () { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); } public static IntPtr AllocObject (string jniClassName) diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs index ad97a401a32..65cbd2ea410 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs @@ -40,7 +40,6 @@ internal struct JnienvInitializeArgs { } #pragma warning restore 0649 - internal static JniRuntime.JniValueManager? ValueManager; internal static bool IsRunningOnDesktop; internal static bool jniRemappingInUse; internal static bool MarshalMethodsEnabled; @@ -88,7 +87,6 @@ static Type TypeGetType (string typeName) => internal static void InitializeJniRuntime (JniRuntime runtime) { androidRuntime = runtime; - ValueManager = runtime.ValueManager; SetSynchronizationContext (); } @@ -115,11 +113,15 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args) JniRuntime.JniValueManager valueManager; if (RuntimeFeature.ManagedTypeMap) { typeManager = new ManagedTypeManager (); - valueManager = new ManagedValueManager (); } else { typeManager = new AndroidTypeManager (args->jniAddNativeMethodRegistrationAttributePresent != 0); - valueManager = RuntimeType == DotNetRuntimeType.MonoVM ? new AndroidValueManager () : new ManagedValueManager (); } + valueManager = RuntimeType switch + { + DotNetRuntimeType.MonoVM => new AndroidValueManager(), + DotNetRuntimeType.CoreCLR => ManagedValueManager.GetOrCreateInstance(), + _ => throw new NotSupportedException ($"No value manager for runtime type: {RuntimeType}"), + }; androidRuntime = new AndroidRuntime ( args->env, args->javaVm, @@ -128,7 +130,6 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args) valueManager, args->jniAddNativeMethodRegistrationAttributePresent != 0 ); - ValueManager = androidRuntime.ValueManager; IsRunningOnDesktop = args->isRunningOnDesktop == 1; diff --git a/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs b/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs index c85e0feec16..9c7244b849a 100644 --- a/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs +++ b/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs @@ -17,7 +17,7 @@ static bool _unhandled_exception (Exception e) internal static void Wrap_JniMarshal_PP_V (this _JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz); } catch (Exception e) when (_unhandled_exception (e)) { @@ -28,7 +28,7 @@ internal static void Wrap_JniMarshal_PP_V (this _JniMarshal_PP_V callback, IntPt internal static int Wrap_JniMarshal_PP_I (this _JniMarshal_PP_I callback, IntPtr jnienv, IntPtr klazz) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz); } catch (Exception e) when (_unhandled_exception (e)) { @@ -39,7 +39,7 @@ internal static int Wrap_JniMarshal_PP_I (this _JniMarshal_PP_I callback, IntPtr internal static bool Wrap_JniMarshal_PP_Z (this _JniMarshal_PP_Z callback, IntPtr jnienv, IntPtr klazz) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz); } catch (Exception e) when (_unhandled_exception (e)) { @@ -50,7 +50,7 @@ internal static bool Wrap_JniMarshal_PP_Z (this _JniMarshal_PP_Z callback, IntPt internal static void Wrap_JniMarshal_PPI_V (this _JniMarshal_PPI_V callback, IntPtr jnienv, IntPtr klazz, int p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -61,7 +61,7 @@ internal static void Wrap_JniMarshal_PPI_V (this _JniMarshal_PPI_V callback, Int internal static IntPtr Wrap_JniMarshal_PPI_L (this _JniMarshal_PPI_L callback, IntPtr jnienv, IntPtr klazz, int p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -72,7 +72,7 @@ internal static IntPtr Wrap_JniMarshal_PPI_L (this _JniMarshal_PPI_L callback, I internal static int Wrap_JniMarshal_PPI_I (this _JniMarshal_PPI_I callback, IntPtr jnienv, IntPtr klazz, int p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -83,7 +83,7 @@ internal static int Wrap_JniMarshal_PPI_I (this _JniMarshal_PPI_I callback, IntP internal static long Wrap_JniMarshal_PPI_J (this _JniMarshal_PPI_J callback, IntPtr jnienv, IntPtr klazz, int p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -94,7 +94,7 @@ internal static long Wrap_JniMarshal_PPI_J (this _JniMarshal_PPI_J callback, Int internal static int Wrap_JniMarshal_PPL_I (this _JniMarshal_PPL_I callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -105,7 +105,7 @@ internal static int Wrap_JniMarshal_PPL_I (this _JniMarshal_PPL_I callback, IntP internal static IntPtr Wrap_JniMarshal_PPL_L (this _JniMarshal_PPL_L callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -116,7 +116,7 @@ internal static IntPtr Wrap_JniMarshal_PPL_L (this _JniMarshal_PPL_L callback, I internal static void Wrap_JniMarshal_PPL_V (this _JniMarshal_PPL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -127,7 +127,7 @@ internal static void Wrap_JniMarshal_PPL_V (this _JniMarshal_PPL_V callback, Int internal static bool Wrap_JniMarshal_PPL_Z (this _JniMarshal_PPL_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -138,7 +138,7 @@ internal static bool Wrap_JniMarshal_PPL_Z (this _JniMarshal_PPL_Z callback, Int internal static bool Wrap_JniMarshal_PPJ_Z (this _JniMarshal_PPJ_Z callback, IntPtr jnienv, IntPtr klazz, long p0) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0); } catch (Exception e) when (_unhandled_exception (e)) { @@ -149,7 +149,7 @@ internal static bool Wrap_JniMarshal_PPJ_Z (this _JniMarshal_PPJ_Z callback, Int internal static void Wrap_JniMarshal_PPII_V (this _JniMarshal_PPII_V callback, IntPtr jnienv, IntPtr klazz, int p0, int p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -160,7 +160,7 @@ internal static void Wrap_JniMarshal_PPII_V (this _JniMarshal_PPII_V callback, I internal static IntPtr Wrap_JniMarshal_PPII_L (this _JniMarshal_PPII_L callback, IntPtr jnienv, IntPtr klazz, int p0, int p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -171,7 +171,7 @@ internal static IntPtr Wrap_JniMarshal_PPII_L (this _JniMarshal_PPII_L callback, internal static void Wrap_JniMarshal_PPLI_V (this _JniMarshal_PPLI_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -182,7 +182,7 @@ internal static void Wrap_JniMarshal_PPLI_V (this _JniMarshal_PPLI_V callback, I internal static void Wrap_JniMarshal_PPLZ_V (this _JniMarshal_PPLZ_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, bool p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -193,7 +193,7 @@ internal static void Wrap_JniMarshal_PPLZ_V (this _JniMarshal_PPLZ_V callback, I internal static void Wrap_JniMarshal_PPLL_V (this _JniMarshal_PPLL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -204,7 +204,7 @@ internal static void Wrap_JniMarshal_PPLL_V (this _JniMarshal_PPLL_V callback, I internal static void Wrap_JniMarshal_PPLF_V (this _JniMarshal_PPLF_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, float p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -215,7 +215,7 @@ internal static void Wrap_JniMarshal_PPLF_V (this _JniMarshal_PPLF_V callback, I internal static IntPtr Wrap_JniMarshal_PPLI_L (this _JniMarshal_PPLI_L callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -226,7 +226,7 @@ internal static IntPtr Wrap_JniMarshal_PPLI_L (this _JniMarshal_PPLI_L callback, internal static IntPtr Wrap_JniMarshal_PPLL_L (this _JniMarshal_PPLL_L callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -237,7 +237,7 @@ internal static IntPtr Wrap_JniMarshal_PPLL_L (this _JniMarshal_PPLL_L callback, internal static bool Wrap_JniMarshal_PPLL_Z (this _JniMarshal_PPLL_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -248,7 +248,7 @@ internal static bool Wrap_JniMarshal_PPLL_Z (this _JniMarshal_PPLL_Z callback, I internal static bool Wrap_JniMarshal_PPIL_Z (this _JniMarshal_PPIL_Z callback, IntPtr jnienv, IntPtr klazz, int p0, IntPtr p1) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1); } catch (Exception e) when (_unhandled_exception (e)) { @@ -259,7 +259,7 @@ internal static bool Wrap_JniMarshal_PPIL_Z (this _JniMarshal_PPIL_Z callback, I internal static void Wrap_JniMarshal_PPIIL_V (this _JniMarshal_PPIIL_V callback, IntPtr jnienv, IntPtr klazz, int p0, int p1, IntPtr p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -270,7 +270,7 @@ internal static void Wrap_JniMarshal_PPIIL_V (this _JniMarshal_PPIIL_V callback, internal static int Wrap_JniMarshal_PPLII_I (this _JniMarshal_PPLII_I callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1, int p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -281,7 +281,7 @@ internal static int Wrap_JniMarshal_PPLII_I (this _JniMarshal_PPLII_I callback, internal static bool Wrap_JniMarshal_PPLII_Z (this _JniMarshal_PPLII_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1, int p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -292,7 +292,7 @@ internal static bool Wrap_JniMarshal_PPLII_Z (this _JniMarshal_PPLII_Z callback, internal static void Wrap_JniMarshal_PPLII_V (this _JniMarshal_PPLII_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1, int p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -303,7 +303,7 @@ internal static void Wrap_JniMarshal_PPLII_V (this _JniMarshal_PPLII_V callback, internal static void Wrap_JniMarshal_PPIII_V (this _JniMarshal_PPIII_V callback, IntPtr jnienv, IntPtr klazz, int p0, int p1, int p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -314,7 +314,7 @@ internal static void Wrap_JniMarshal_PPIII_V (this _JniMarshal_PPIII_V callback, internal static bool Wrap_JniMarshal_PPLLJ_Z (this _JniMarshal_PPLLJ_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, long p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -325,7 +325,7 @@ internal static bool Wrap_JniMarshal_PPLLJ_Z (this _JniMarshal_PPLLJ_Z callback, internal static void Wrap_JniMarshal_PPILL_V (this _JniMarshal_PPILL_V callback, IntPtr jnienv, IntPtr klazz, int p0, IntPtr p1, IntPtr p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -336,7 +336,7 @@ internal static void Wrap_JniMarshal_PPILL_V (this _JniMarshal_PPILL_V callback, internal static bool Wrap_JniMarshal_PPLIL_Z (this _JniMarshal_PPLIL_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1, IntPtr p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -347,7 +347,7 @@ internal static bool Wrap_JniMarshal_PPLIL_Z (this _JniMarshal_PPLIL_Z callback, internal static void Wrap_JniMarshal_PPLLL_V (this _JniMarshal_PPLLL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, IntPtr p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -358,7 +358,7 @@ internal static void Wrap_JniMarshal_PPLLL_V (this _JniMarshal_PPLLL_V callback, internal static IntPtr Wrap_JniMarshal_PPLLL_L (this _JniMarshal_PPLLL_L callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, IntPtr p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -369,7 +369,7 @@ internal static IntPtr Wrap_JniMarshal_PPLLL_L (this _JniMarshal_PPLLL_L callbac internal static bool Wrap_JniMarshal_PPLLL_Z (this _JniMarshal_PPLLL_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, IntPtr p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -380,7 +380,7 @@ internal static bool Wrap_JniMarshal_PPLLL_Z (this _JniMarshal_PPLLL_Z callback, internal static IntPtr Wrap_JniMarshal_PPIZI_L (this _JniMarshal_PPIZI_L callback, IntPtr jnienv, IntPtr klazz, int p0, bool p1, int p2) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2); } catch (Exception e) when (_unhandled_exception (e)) { @@ -391,7 +391,7 @@ internal static IntPtr Wrap_JniMarshal_PPIZI_L (this _JniMarshal_PPIZI_L callbac internal static void Wrap_JniMarshal_PPIIII_V (this _JniMarshal_PPIIII_V callback, IntPtr jnienv, IntPtr klazz, int p0, int p1, int p2, int p3) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2, p3); } catch (Exception e) when (_unhandled_exception (e)) { @@ -402,7 +402,7 @@ internal static void Wrap_JniMarshal_PPIIII_V (this _JniMarshal_PPIIII_V callbac internal static void Wrap_JniMarshal_PPLLLL_V (this _JniMarshal_PPLLLL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, IntPtr p2, IntPtr p3) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2, p3); } catch (Exception e) when (_unhandled_exception (e)) { @@ -413,7 +413,7 @@ internal static void Wrap_JniMarshal_PPLLLL_V (this _JniMarshal_PPLLLL_V callbac internal static bool Wrap_JniMarshal_PPLZZL_Z (this _JniMarshal_PPLZZL_Z callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, bool p1, bool p2, IntPtr p3) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { return callback (jnienv, klazz, p0, p1, p2, p3); } catch (Exception e) when (_unhandled_exception (e)) { @@ -424,7 +424,7 @@ internal static bool Wrap_JniMarshal_PPLZZL_Z (this _JniMarshal_PPLZZL_Z callbac internal static void Wrap_JniMarshal_PPLIIII_V (this _JniMarshal_PPLIIII_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1, int p2, int p3, int p4) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2, p3, p4); } catch (Exception e) when (_unhandled_exception (e)) { @@ -435,7 +435,7 @@ internal static void Wrap_JniMarshal_PPLIIII_V (this _JniMarshal_PPLIIII_V callb internal static void Wrap_JniMarshal_PPZIIII_V (this _JniMarshal_PPZIIII_V callback, IntPtr jnienv, IntPtr klazz, bool p0, int p1, int p2, int p3, int p4) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2, p3, p4); } catch (Exception e) when (_unhandled_exception (e)) { @@ -446,7 +446,7 @@ internal static void Wrap_JniMarshal_PPZIIII_V (this _JniMarshal_PPZIIII_V callb internal static void Wrap_JniMarshal_PPLIIIIIIII_V (this _JniMarshal_PPLIIIIIIII_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { callback (jnienv, klazz, p0, p1, p2, p3, p4, p5, p6, p7, p8); } catch (Exception e) when (_unhandled_exception (e)) { diff --git a/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.tt b/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.tt index 0dc1e4e9810..425dd99bcdb 100644 --- a/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.tt +++ b/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.tt @@ -268,7 +268,7 @@ foreach (var info in delegateTypes) { #> internal static <#= info.Return #> Wrap<#= info.Type #> (this <#= info.Type #> callback, <#= info.Signature #>) { - JNIEnvInit.ValueManager?.WaitForGCBridgeProcessing (); + Java.Interop.JniEnvironment.Runtime.ValueManager.WaitForGCBridgeProcessing (); try { <#= info.Return != "void" ? "return " : "" #>callback (<#= info.Invoke #>); } catch (Exception e) when (_unhandled_exception (e)) { diff --git a/src/Mono.Android/Java.Interop/Runtime.cs b/src/Mono.Android/Java.Interop/Runtime.cs index 8d69aedffa4..314815a9edb 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.ValueManager!.GetSurfacedPeers (); + var peers = JniEnvironment.Runtime.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.Lang/Object.cs b/src/Mono.Android/Java.Lang/Object.cs index 58a7e54d88b..44c9519fb4d 100644 --- a/src/Mono.Android/Java.Lang/Object.cs +++ b/src/Mono.Android/Java.Lang/Object.cs @@ -111,7 +111,7 @@ protected void SetHandle (IntPtr value, JniHandleOwnership transfer) { var reference = new JniObjectReference (value); var options = FromJniHandleOwnership (transfer); - JNIEnvInit.ValueManager?.ConstructPeer ( + JniEnvironment.Runtime.ValueManager.ConstructPeer ( this, ref reference, value == IntPtr.Zero ? JniObjectReferenceOptions.None : options); @@ -128,7 +128,7 @@ static JniObjectReferenceOptions FromJniHandleOwnership (JniHandleOwnership tran internal static IJavaPeerable? PeekObject (IntPtr handle, Type? requiredType = null) { - var peeked = JNIEnvInit.ValueManager?.PeekPeer (new JniObjectReference (handle)); + var peeked = JniEnvironment.Runtime.ValueManager.PeekPeer (new JniObjectReference (handle)); if (peeked == null) return null; if (requiredType != null && !requiredType.IsAssignableFrom (peeked.GetType ())) @@ -180,7 +180,7 @@ internal static T? _GetObject< if (handle == IntPtr.Zero) return null; - var r = JNIEnvInit.ValueManager!.GetPeer (new JniObjectReference (handle), type); + var r = JniEnvironment.Runtime.ValueManager.GetPeer (new JniObjectReference (handle), type); JNIEnv.DeleteRef (handle, transfer); return r; } diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs index c58cfbab431..5d517c381c1 100644 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs +++ b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs @@ -22,7 +22,10 @@ class ManagedValueManager : JniRuntime.JniValueManager Dictionary>? RegisteredInstances = new Dictionary>(); - internal ManagedValueManager () + static Lazy s_instance = new (() => new ManagedValueManager ()); + public static ManagedValueManager GetOrCreateInstance () => s_instance.Value; + + ManagedValueManager () { } diff --git a/src/Mono.Android/Microsoft.Android.Runtime/SimpleValueManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/SimpleValueManager.cs new file mode 100644 index 00000000000..57d8ef5f84d --- /dev/null +++ b/src/Mono.Android/Microsoft.Android.Runtime/SimpleValueManager.cs @@ -0,0 +1,294 @@ +// Originally from: https://github.com/dotnet/java-interop/blob/9b1d8781e8e322849d05efac32119c913b21c192/src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.cs +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using Android.Runtime; +using Java.Interop; + +namespace Microsoft.Android.Runtime; + +class SimpleValueManager : JniRuntime.JniValueManager +{ + const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + + Dictionary>? RegisteredInstances = new Dictionary>(); + + internal SimpleValueManager () + { + } + + public override void WaitForGCBridgeProcessing () + { + } + + public override void CollectPeers () + { + if (RegisteredInstances == null) + throw new ObjectDisposedException (nameof (SimpleValueManager)); + + var peers = new List (); + + lock (RegisteredInstances) { + foreach (var ps in RegisteredInstances.Values) { + foreach (var p in ps) { + peers.Add (p); + } + } + RegisteredInstances.Clear (); + } + List? exceptions = null; + foreach (var peer in peers) { + try { + peer.Dispose (); + } + catch (Exception e) { + exceptions = exceptions ?? new List (); + exceptions.Add (e); + } + } + if (exceptions != null) + throw new AggregateException ("Exceptions while collecting peers.", exceptions); + } + + public override void AddPeer (IJavaPeerable value) + { + if (RegisteredInstances == null) + throw new ObjectDisposedException (nameof (SimpleValueManager)); + + var r = value.PeerReference; + if (!r.IsValid) + throw new ObjectDisposedException (value.GetType ().FullName); + + if (r.Type != JniObjectReferenceType.Global) { + value.SetPeerReference (r.NewGlobalRef ()); + JniObjectReference.Dispose (ref r, JniObjectReferenceOptions.CopyAndDispose); + } + int key = value.JniIdentityHashCode; + lock (RegisteredInstances) { + List? peers; + if (!RegisteredInstances.TryGetValue (key, out peers)) { + peers = new List () { + value, + }; + RegisteredInstances.Add (key, peers); + return; + } + + for (int i = peers.Count - 1; i >= 0; i--) { + var p = peers [i]; + if (!JniEnvironment.Types.IsSameObject (p.PeerReference, value.PeerReference)) + continue; + if (Replaceable (p)) { + peers [i] = value; + } else { + WarnNotReplacing (key, value, p); + } + return; + } + peers.Add (value); + } + } + + static bool Replaceable (IJavaPeerable peer) + { + if (peer == null) + return true; + return peer.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable); + } + + void WarnNotReplacing (int key, IJavaPeerable ignoreValue, IJavaPeerable keepValue) + { + Runtime.ObjectReferenceManager.WriteGlobalReferenceLine ( + "Warning: Not registering PeerReference={0} IdentityHashCode=0x{1} Instance={2} Instance.Type={3} Java.Type={4}; " + + "keeping previously registered PeerReference={5} Instance={6} Instance.Type={7} Java.Type={8}.", + ignoreValue.PeerReference.ToString (), + key.ToString ("x", CultureInfo.InvariantCulture), + RuntimeHelpers.GetHashCode (ignoreValue).ToString ("x", CultureInfo.InvariantCulture), + ignoreValue.GetType ().FullName, + JniEnvironment.Types.GetJniTypeNameFromInstance (ignoreValue.PeerReference), + keepValue.PeerReference.ToString (), + RuntimeHelpers.GetHashCode (keepValue).ToString ("x", CultureInfo.InvariantCulture), + keepValue.GetType ().FullName, + JniEnvironment.Types.GetJniTypeNameFromInstance (keepValue.PeerReference)); + } + + public override IJavaPeerable? PeekPeer (JniObjectReference reference) + { + if (RegisteredInstances == null) + throw new ObjectDisposedException (nameof (SimpleValueManager)); + + if (!reference.IsValid) + return null; + + int key = GetJniIdentityHashCode (reference); + + lock (RegisteredInstances) { + List? peers; + if (!RegisteredInstances.TryGetValue (key, out peers)) + return null; + + for (int i = peers.Count - 1; i >= 0; i--) { + var p = peers [i]; + if (JniEnvironment.Types.IsSameObject (reference, p.PeerReference)) + return p; + } + if (peers.Count == 0) + RegisteredInstances.Remove (key); + } + return null; + } + + public override void RemovePeer (IJavaPeerable value) + { + if (RegisteredInstances == null) + throw new ObjectDisposedException (nameof (SimpleValueManager)); + + if (value == null) + throw new ArgumentNullException (nameof (value)); + + int key = value.JniIdentityHashCode; + lock (RegisteredInstances) { + List? peers; + if (!RegisteredInstances.TryGetValue (key, out peers)) + return; + + for (int i = peers.Count - 1; i >= 0; i--) { + var p = peers [i]; + if (object.ReferenceEquals (value, p)) { + peers.RemoveAt (i); + } + } + if (peers.Count == 0) + RegisteredInstances.Remove (key); + } + } + + public override void FinalizePeer (IJavaPeerable value) + { + var h = value.PeerReference; + var o = Runtime.ObjectReferenceManager; + // MUST NOT use SafeHandle.ReferenceType: local refs are tied to a JniEnvironment + // and the JniEnvironment's corresponding thread; it's a thread-local value. + // Accessing SafeHandle.ReferenceType won't kill anything (so far...), but + // instead it always returns JniReferenceType.Invalid. + if (!h.IsValid || h.Type == JniObjectReferenceType.Local) { + if (o.LogGlobalReferenceMessages) { + o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}", + h.ToString (), + value.JniIdentityHashCode.ToString ("x", CultureInfo.InvariantCulture), + RuntimeHelpers.GetHashCode (value).ToString ("x", CultureInfo.InvariantCulture), + value.GetType ().ToString ()); + } + RemovePeer (value); + value.SetPeerReference (new JniObjectReference ()); + value.Finalized (); + return; + } + + RemovePeer (value); + if (o.LogGlobalReferenceMessages) { + o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}", + h.ToString (), + value.JniIdentityHashCode.ToString ("x", CultureInfo.InvariantCulture), + RuntimeHelpers.GetHashCode (value).ToString ("x", CultureInfo.InvariantCulture), + value.GetType ().ToString ()); + } + value.SetPeerReference (new JniObjectReference ()); + JniObjectReference.Dispose (ref h); + value.Finalized (); + } + + public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues) + { + try { + ActivateViaReflection (reference, cinfo, argumentValues); + } catch (Exception e) { + var m = string.Format ( + CultureInfo.InvariantCulture, + "Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", + reference, + GetJniIdentityHashCode (reference).ToString ("x", CultureInfo.InvariantCulture), + JniEnvironment.Types.GetJniTypeNameFromInstance (reference), + cinfo.DeclaringType?.FullName); + Debug.WriteLine (m); + + throw new NotSupportedException (m, e); + } + } + + void ActivateViaReflection (JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues) + { + var declType = GetDeclaringType (cinfo); + +#pragma warning disable IL2072 + var self = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declType); +#pragma warning restore IL2072 + self.SetPeerReference (reference); + + cinfo.Invoke (self, argumentValues); + + [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "🤷‍♂️")] + [return: DynamicallyAccessedMembers (Constructors)] + Type GetDeclaringType (ConstructorInfo cinfo) => + cinfo.DeclaringType ?? throw new NotSupportedException ("Do not know the type to create!"); + } + + public override List GetSurfacedPeers () + { + if (RegisteredInstances == null) + throw new ObjectDisposedException (nameof (SimpleValueManager)); + + lock (RegisteredInstances) { + var peers = new List (RegisteredInstances.Count); + foreach (var e in RegisteredInstances) { + foreach (var p in e.Value) { + peers.Add (new JniSurfacedPeerInfo (e.Key, new WeakReference (p))); + } + } + return peers; + } + } + + const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + + static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) }; + + protected override bool TryConstructPeer ( + IJavaPeerable self, + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type type) + { + var c = type.GetConstructor (ActivationConstructorBindingFlags, null, XAConstructorSignature, null); + if (c != null) { + var args = new object[] { + reference.Handle, + JniHandleOwnership.DoNotTransfer, + }; + c.Invoke (self, args); + JniObjectReference.Dispose (ref reference, options); + return true; + } + return base.TryConstructPeer (self, ref reference, options, type); + } + + protected override bool TryUnboxPeerObject (IJavaPeerable value, [NotNullWhen (true)]out object? result) + { + var proxy = value as JavaProxyThrowable; + if (proxy != null) { + result = proxy.InnerException; + return true; + } + return base.TryUnboxPeerObject (value, out result); + } +} diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index ec9eff97c93..a3d26c20b45 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -353,6 +353,7 @@ +