Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[monodroid] Handle managed -> Java duplicate type mapping correctly (d…
…otnet#5459) Fixes: dotnet#5409 Context: a017561 Context: bb55bb0 Yet Another Java :: Managed Type Aliasing Issue. Type aliasing occurs when multiple managed types bind the same Java type. One common scenario for this is for `abstract` classes: // Java: public abstract class LayoutInflater { // … } // C# Binding [Register ("android/view/LayoutInflater", DoNotGenerateAcw=true)] public abstract class LayoutInflater : Java.Lang.Object { static readonly JniPeerMembers _members = new XAPeerMembers ("android/view/LayoutInflater", typeof (LayoutInflater)); } // Used at runtime [Register ("android/view/LayoutInflater", DoNotGenerateAcw=true)] internal partial class LayoutInflaterInvoker : LayoutInflater { static readonly JniPeerMembers _members = new XAPeerMembers ("android/view/LayoutInflater", typeof (LayoutInflaterInvoker)); } Both the C# `LayoutInflater` and `LayoutInflaterInvoker` types *alias* the Java `LayoutInflater` type. In a *Debug* configuration build, the mappings between the Java types and Managed types is held within a per-assembly mapping (7117414), and because of a017561 there is no explicit managed entry for `LayoutInflaterInvoker`: DebugTypemap = { .java_to_managed = { { "android/view/LayoutInflater", 0 }, // Java LayoutInflater -> C# LayoutInflater { "android/view/LayoutInflater", 0 }, // Java LayoutInflater -> C# LayoutInflater }, .managed_to_java = { { "Android.Views.LayoutInflater", 0 }, // C# LayoutInflater -> Java LayoutInflater { "Android.Views.LayoutInflater", 0 }, // C# LayoutInflaterInvoker -> Java LayoutInflater }, } At *runtime* when the `LayoutInflaterInvoker` static constructor is executed, we hit an [assert in the `JniPeerMembers` constructor][0]: app_process32: ---- DEBUG ASSERTION FAILED ---- app_process32: ---- Assert Short Message ---- app_process32: ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof(Android.Views.LayoutInflaterInvoker)).JniTypeName="" != "android/view/LayoutInflater" app_process32: ---- Assert Long Message ---- app_process32: app_process32: at System.Diagnostics.DebugProvider.Fail(String message, String detailMessage) app_process32: at System.Diagnostics.Debug.Fail(String message, String detailMessage) app_process32: at System.Diagnostics.Debug.Assert(Boolean condition, String message, String detailMessage) app_process32: at System.Diagnostics.Debug.Assert(Boolean condition, String message) app_process32: at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean checkManagedPeerType, Boolean isInterface) app_process32: at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) app_process32: at Android.Runtime.XAPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) app_process32: at Android.Views.LayoutInflaterInvoker..cctor() app_process32: at System.Reflection.RuntimeConstructorInfo.InternalInvoke(RuntimeConstruct : CLR: Managed code called FailFast, saying "ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof(Android.Views.LayoutInflaterInvoker)).JniTypeName="" != "android/view/LayoutInflater" : at System.Diagnostics.DebugProvider.Fail(String message, String detailMessage) : at System.Diagnostics.Debug.Fail(String message, String detailMessage) : at System.Diagnostics.Debug.Assert(Boolean condition, String message, String detailMessage) : at System.Diagnostics.Debug.Assert(Boolean condition, String message) : at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean checkManagedPeerType, Boolean isInterface) : at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) : at Android.Runtime.XAPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) : at Android.Views.LayoutInflaterInvoker..cctor() The cause of the assertion failure is because the `.managed_to_java` table doesn't contain an entry for `LayoutInflaterInvoker`. The fix is to modify a017561 behavior and *retain* the `*Invoker` types in the `.managed_to_java` table: DebugTypemap = { .java_to_managed = { { "android/view/LayoutInflater", 0 }, // Java LayoutInflater -> C# LayoutInflater { "android/view/LayoutInflater", 0 }, // Java LayoutInflater -> C# LayoutInflater }, .managed_to_java = { { "Android.Views.LayoutInflater", 0 }, // C# LayoutInflater -> Java LayoutInflater { "Android.Views.LayoutInflaterInvoker", 0 }, // C# LayoutInflaterInvoker -> Java LayoutInflater }, } This ensures that we can appropriately obtain a Java type name for the `LayoutInflaterInvoker` type, fixing the assert. [0]: https://github.com/xamarin/java.interop/blob/3894cd76f71f618949c8542f0edd95762e22881f/src/Java.Interop/Java.Interop/JniPeerMembers.cs#L29
- Loading branch information