From 95f7ae5890dec0c1e4cd1af8dbdded2f9b8f380b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 21 Apr 2021 18:26:18 +0200 Subject: [PATCH 1/2] Include interfaces in type maps Java typemaps have never included interfaces because, till very recently, they couldn't contain methods so they couldn't have been used as method invocation targets. With the addition of DIM (Default Interface Methods) to C# this is no longer true. Exclusion of interfaces from typemaps can lead to errors similar to: ---- DEBUG ASSERTION FAILED ---- ---- Assert Short Message ---- ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof(Android.App.Application+IActivityLifecycleCallbacks)).JniTypeName="" != "android/app/Application$ActivityLifecycleCallbacks" ---- Assert Long Message ---- at System.Diagnostics.DebugProvider.Fail(String message, String detailMessage) in System.Private.CoreLib.dll:token 0x6005586+0x0 at System.Diagnostics.Debug.Fail(String message, String detailMessage) in System.Private.CoreLib.dll:token 0x6005548+0x0 at System.Diagnostics.Debug.Assert(Boolean condition, String message, String detailMessage) in System.Private.CoreLib.dll:token 0x6005545+0x0 at System.Diagnostics.Debug.Assert(Boolean condition, String message) in System.Private.CoreLib.dll:token 0x6005544+0x0 at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean checkManagedPeerType, Boolean isInterface) in Java.Interop.dll:token 0x600032e+0x0 at Java.Interop.JniPe Process terminated due to "ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof(Android.App.Application+IActivityLifecycleCallbacks)).JniTypeName="" != "android/app/Application$ActivityLifecycleCallbacks" at System.Diagnostics.DebugProvider.Fail(String message, String detailMessage) in System.Private.CoreLib.dll:token 0x6005586+0x0 at System.Diagnostics.Debug.Fail(String message, String detailMessage) in System.Private.CoreLib.dll:token 0x6005548+0x0 at System.Diagnostics.Debug.Assert(Boolean condition, String message, String detailMessage) in System.Private.CoreLib.dll:token 0x6005545+0x0 at System.Diagnostics.Debug.Assert(Boolean condition, String message) in System.Private.CoreLib.dll:token 0x6005544+0x0 at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean checkManagedPeerType, Boolean isInterface) in Java.Interop.dll:token 0x600032e+0x0 at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean isInterface) in Java.Interop.dll:token 0x600032c+0x0 at Android.Runtime.XAPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean isInterface) in Mono.Android.dll:token 0x6017ed3+0x0 at Android.App.Application.IActivityLifecycleCallbacks..cctor() in Mono.Android.dll:token 0x6025027+0x0 at Android.Runtime.AndroidTypeManager.RegisterNativeMembers(JniType nativeClass, Type type, String methods) in Mono.Android.dll:token 0x6017c19+0x0 at Android.Runtime.JNIEnv.RegisterJniNatives(IntPtr typeName_ptr, Int32 typeName_len, IntPtr jniClass, IntPtr methods_ptr, Int32 methods_len) in Mono.Android.dll:token 0x6017d48+0x0 at Java.Interop.NativeMethods.java_interop_jnienv_alloc_object(IntPtr , IntPtr& , IntPtr ) in Java.Interop.dll:token 0x0+0x0 at Java.Interop.JniEnvironment.Object.AllocObject(JniObjectReference type) in Java.Interop.dll:token 0x6000563+0x0 at Java.Interop.JniType.AllocObject() in Java.Interop.dll:token 0x60003a1+0x0 at Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(String constructorSignature, Type declaringType, JniArgumentValue* parameters) in Java.Interop.dll:token 0x60005e5+0x0 at Java.Lang.Object..ctor() in Mono.Android.dll:token 0x601ea58+0x0 at Microsoft.Maui.MauiApplication.ActivityLifecycleCallbacks..ctor() in Microsoft.Maui.dll:token 0x60004ef+0x0 at Microsoft.Maui.MauiApplication`1[[HelloMaui.Startup, HelloMaui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCreate() in Microsoft.Maui.dll:token 0x6000114+0x0 at Android.App.Application.n_OnCreate(IntPtr jnienv, IntPtr native__this) in Mono.Android.dll:token 0x60153c7+0x0 at Android.Runtime.DynamicMethodNameCounter.1(IntPtr , IntPtr ) in Mono.Android.dll:token 0x0+0x0" This is caused by the fact that a class (`MauiApplication.ActivityLifecycleCallbacks` in this case) implements a Java interace (`IActivityLifecycleCallbacks` here) but it does not implement all the interface memebers. In such instance, the default interface methods will be called (if available). Xamarin.Android pairs each Java interface with a class, called an Invoker, which is used for actual invocation of the interface methods. In the case of the above crash, however, the `IActivityLifecycleCallbacksInvoker` class doesn't implement one of the `IActivityLifecycleCallbacks` interface methods (`OnActivityPostCreated`) which causes `Android.Runtime.AndroidTypeManager.RegisterNativeMembers` to attempt to invoke the default method in `IActivityLifecycleCallbacks`. This, in turn, leads to `XAPeerMembers` attempting to map its owner's managed type (`IActivityLifecycleCallbacks`) to its Java counterpart by using a typemap lookup. However, since interfaces aren't present in typemaps, the lookup fails and we get the above exception. Fix the issue by including all interfaces implementing the `Java.Interop.IJavaPeerable` interface in typemaps. --- .../Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs index 49fc8ca2d..7af81d223 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs @@ -50,8 +50,7 @@ public List GetJavaTypes (IEnumerable assemblies, IAssem void AddJavaTypes (List javaTypes, TypeDefinition type) { - if (type.IsSubclassOf ("Java.Lang.Object", cache) || type.IsSubclassOf ("Java.Lang.Throwable", cache)) { - + if (type.IsSubclassOf ("Java.Lang.Object", cache) || type.IsSubclassOf ("Java.Lang.Throwable", cache) || (type.IsInterface && type.ImplementsInterface ("Java.Interop.IJavaPeerable", cache))) { // For subclasses of e.g. Android.App.Activity. javaTypes.Add (type); } else if (type.IsClass && !type.IsSubclassOf ("System.Exception", cache) && type.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) { From 28c03672cdc32b5e6d8b88db06b5904a1ef0d01b Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Wed, 21 Apr 2021 13:42:16 -0400 Subject: [PATCH 2/2] avoid long lines --- .../JavaTypeScanner.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs index 7af81d223..f85427e70 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs @@ -50,10 +50,12 @@ public List GetJavaTypes (IEnumerable assemblies, IAssem void AddJavaTypes (List javaTypes, TypeDefinition type) { - if (type.IsSubclassOf ("Java.Lang.Object", cache) || type.IsSubclassOf ("Java.Lang.Throwable", cache) || (type.IsInterface && type.ImplementsInterface ("Java.Interop.IJavaPeerable", cache))) { + if (type.IsSubclassOf ("Java.Lang.Object", cache) || + type.IsSubclassOf ("Java.Lang.Throwable", cache) || + (type.IsInterface && type.ImplementsInterface ("Java.Interop.IJavaPeerable", cache))) { // For subclasses of e.g. Android.App.Activity. javaTypes.Add (type); - } else if (type.IsClass && !type.IsSubclassOf ("System.Exception", cache) && type.ImplementsInterface ("Android.Runtime.IJavaObject", cache)) { + } else if (type.IsClass && !type.IsSubclassOf ("System.Exception", cache) && type.ImplementsInterface ("Android.Runtime.IJa", cache)) { var level = ErrorOnCustomJavaObject ? TraceLevel.Error : TraceLevel.Warning; var prefix = ErrorOnCustomJavaObject ? "error" : "warning"; Logger (