Skip to content

Conversation

@grendello
Copy link
Contributor

@grendello grendello commented Apr 21, 2021

Context: dotnet/java-interop@ebd7d76
Context: dotnet/java-interop@f9faaab

With Java.Interop Java type scanner now including Java interfaces in
the returned set of types, we need to ignore interfaces when generating
JCWs.

@grendello grendello requested a review from jonpryor April 21, 2021 16:43
@grendello grendello added the do-not-merge PR should not be merged. label Apr 21, 2021
jonpryor pushed a commit to dotnet/java-interop that referenced this pull request Apr 21, 2021
…maps (#824)

Context: 29f9707
Context: dotnet/android#5859

Java typemaps (38a1a2c) have never included interfaces because,
until very recently (29f9707), they couldn't contain methods, and
thus they couldn't have been used as method invocation targets.  With
the addition of Default Interface Methods, this is no longer true.

The setup:

	// 3fcc714, a27a5c2, …
	namespace Java.Interop {
	  partial class JniPeerMembers {
	    JniPeerMembers (string jniPeerType, Type managedPeerType, bool checkManagedPeerType)
	    {
	      …
	      Debug.Assert (
	          JniEnvironment.Runtime.TypeManager.GetTypeSignature (managedPeerType).JniTypeName == jniPeerType
	          $"ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof({managedPeerType.FullName})).JniTypeName=\"{JniEnvironment.Current.JavaVM.GetJniTypeInfoForType (managedPeerType).JniTypeName}\" != \"{jniPeerType}\"
	    }
	  }
	}

	// generated in xamarin-android
	namespace Android.App {
	  public partial class Application {
	    public partial interface IActivityLifecycleCallbacks : IJavaObject, IJavaPeerable {
	      private static readonly JniPeerMembers _members = new JniPeerMembers ("android/app/Application$ActivityLifecycleCallbacks", typeof (IActivityLifecycleCallbacks), isInterface: true);
	    }
	  }
	}

	// https://github.com/dotnet/maui/blob/18e0f4ebbcca7c904ccdb67e6439cb72382e2a40/src/Core/src/Platform/Android/MauiApplication.cs#L56-L79
	namespace Microsoft.Maui {
	  public partial class MauiApplication : Application {
	    public class ActivityLifecycleCallbacks : Java.Lang.Object, IActivityLifecycleCallbacks {
	      // …
	    }
	  }
	}

The punch; at runtime, with .NET 6, when using a *Debug* build of
`Java.Interop.dll`, the app crashes with an assertion failure when
instantiating the `MauiApplication.ActivityLifecycleCallbacks` type:

	---- 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 interface (`IActivityLifecycleCallbacks` here) but it does not
implement all the interface members.  In such an instance, the default
interface methods may be called (if available), and calling the
Java default interface methods causes the `IActivityLifecycleCallbacks`
static constructor to run, which in turn initializes
`IActivityLifecycleCallbacks._members`, which constructs its
corresponding `JniPeerMembers` instance, triggering the assert.

The assert fails because the type maps don't include bound Java
interfaces, and thus `JniTypeManager.GetTypeSignature (managedPeerType)`
returns a default (empty, unset) value.  This in turn means that
`JniTypeSignature.JniTypeName` is the empty string, which *doesn't*
match the `jniPeerType` parameter.

Fix the assert by including all interfaces implementing the
`Java.Interop.IJavaPeerable` interface within typemaps.
This ensures that `JniTypeManager.GetTypeSignature(Type)` will work
when given an bound interface type.
@grendello grendello force-pushed the interfaces-in-typemaps branch from 415e5ff to 673fc62 Compare April 21, 2021 20:46
@grendello grendello marked this pull request as draft April 21, 2021 20:52
@grendello
Copy link
Contributor Author

Something's wrong locally with this PR, I get an error I didn't get before (this is during XA build, not application build):

bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/jcw-gen.exe" -v10 -o "src/Mono.Android/obj/Release/netcoreapp3.1/android-30/jcw/src" -L "bin/Release/lib/xamarin.android/xbuild-frameworks/Microsoft.Android/netcoreapp3.1/" -L "~/.nuget/packages/microsoft.netcore.app.ref/3.1.0/ref/netcoreapp3.1/" "bin/Release/lib/xamarin.android/xbuild-frameworks/Microsoft.Android/netcoreapp3.1/Mono.Android.dll"
  jcw-gen: Java.Interop.Tools.Diagnostics.XamarinAndroidException: error XA4200: Cannot generate Java wrapper for type 'Org.XmlPull.V1.IXmlPullParser'. Only 'class' types are supported.
    at Java.Interop.Tools.Diagnostics.Diagnostic.Error (System.Int32 code, Mono.Cecil.Cil.SequencePoint location, System.String message, System.Object[] args) [0x00000] in external/Java.Interop/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs:153 
    at Java.Interop.Tools.JavaCallableWrappers.JavaCallableWrapperGenerator..ctor (Mono.Cecil.TypeDefinition type, System.String outerType, System.Action`2[T1,T2] log, Java.Interop.Tools.Cecil.TypeDefinitionCache cache) [0x0007f] in external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs:113 
    at Java.Interop.Tools.JavaCallableWrappers.JavaCallableWrapperGenerator..ctor (Mono.Cecil.TypeDefinition type, System.Action`2[T1,T2] log, Java.Interop.Tools.Cecil.TypeDefinitionCache cache) [0x00000] in external/Java.Interop/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs:65 
    at Java.Interop.Tools.App.GenerateJavaCallableWrapper (Mono.Cecil.TypeDefinition type, System.String outputPath, Java.Interop.Tools.Cecil.TypeDefinitionCache cache) [0x00000] in external/Java.Interop/tools/jcw-gen/App.cs:86 
    at Java.Interop.Tools.App.Main (System.String[] args) [0x00215] in Java.Interop/tools/jcw-gen/App.cs:71

I'll work on it tomorrow

@grendello
Copy link
Contributor Author

The above error is fixed by dotnet/java-interop#825

@grendello grendello marked this pull request as ready for review April 22, 2021 11:47
@grendello grendello force-pushed the interfaces-in-typemaps branch from 673fc62 to dc3c01e Compare April 22, 2021 15:07
Context: dotnet/java-interop@ebd7d76
Context: dotnet/java-interop@f9faaab

With `Java.Interop` Java type scanner now including Java interfaces in
the returned set of types, we need to ignore interfaces when generating
JCWs.
@grendello grendello force-pushed the interfaces-in-typemaps branch from dc3c01e to ce92ed6 Compare April 22, 2021 15:10
@grendello grendello removed the do-not-merge PR should not be merged. label Apr 22, 2021
@jonpryor jonpryor merged commit ccaeec1 into dotnet:main Apr 22, 2021
@grendello grendello deleted the interfaces-in-typemaps branch April 22, 2021 22:20
@github-actions github-actions bot locked and limited conversation to collaborators Jan 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants