Description
Context: #4596 (comment)
Steps to reproduce
- Download and unzip the attached test case.
- Ensure that a hardware device is attached and that
adb
is running. -
msbuild -restore -p:Configuration=Release -t:Install AndroidSingleViewApp1\AndroidSingleViewApp1.csproj
- Launch the app by tapping the app icon on the target device.
Test case: JavaToManagedDuplicatesRelease.zip
Test case details
The test case uses a bindings library for a single Java class. The original Java class is defined as:
package com.contoso.javalibrary1;
public class Class1 {
public static Class1 Create()
{
return new Class1();
}
}
The library adds a generic subclass of the binding in C#:
[Register("com/contoso/javalibrary1/Class1", DoNotGenerateAcw = true)]
public partial class Class0<T> : Class1
{
public Class0(IntPtr handle, JniHandleOwnership transfer)
: base(handle, transfer)
{
}
}
This subclass intentionally uses 0
in the name to try to make JavaTypeScanner.GetJavaTypes()
list it first.
Expected behavior
When built with Xamarin.Android 10.2, the application launches successfully and displays Hello World! in the center of the view.
Actual behavior
When built with Xamarin.Android 10.3, the application exits during launch:
FATAL EXCEPTION: main
Process: com.companyname.androidsingleviewapp1, PID: 24068
android.runtime.JavaProxyThrowable: System.MemberAccessException: Cannot create an instance of Com.Contoso.Javalibrary1.Class0`1[T] because Type.ContainsGenericParameters is true.
at System.Reflection.RuntimeConstructorInfo.DoInvoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00054] in <78d6f78df71a498abab079fd455ad967>:0
at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <78d6f78df71a498abab079fd455ad967>:0
at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters) [0x00000] in <78d6f78df71a498abab079fd455ad967>:0
at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) [0x0001b] in <2ccd59583214493fb4df51106833c4d9>:0
at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType) [0x00111] in <2ccd59583214493fb4df51106833c4d9>:0
at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type) [0x00023] in <2ccd59583214493fb4df51106833c4d9>:0
at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) [0x00017] in <2ccd59583214493fb4df51106833c4d9>:0
at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) [0x00000] in <2ccd59583214493fb4df51106833c4d9>:0
at Com.Contoso.Javalibrary1.Class1.Create () [0x0001e] in <8dad429b6bb14f3ab7952159824bc769>:0
at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState) [0x00012] in <dc89185e1acd4e22bcef03b0baa45e56>:0
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState) [0x0000f] in <2ccd59583214493fb4df51106833c4d9>:0
at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.1(intptr,intptr,intptr)
at crc647d7dcab8da8ee782.MainActivity.n_onCreate(Native Method)
at crc647d7dcab8da8ee782.MainActivity.onCreate(MainActivity.java:29)
at android.app.Activity.performCreate(Activity.java:7144)
at android.app.Activity.performCreate(Activity.java:7135)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2931)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3086)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Preliminary investigation
It appears the issue is that JavaTypeScanner.GetJavaTypes()
returns Class0<T>
earlier in the list than Class1
during <GenerateJavaStubs/>
:
Here's an excerpt of the values I see in allJavaTypes
in my local debugging session:
[198] {Com.Contoso.Javalibrary1.Class0`1} Mono.Cecil.TypeDefinition
[199] {Com.Contoso.Javalibrary1.BuildConfig} Mono.Cecil.TypeDefinition
[200] {Com.Contoso.Javalibrary1.Class1} Mono.Cecil.TypeDefinition
The types are passed in this same order to TypeMapGenerator.GenerateRelease()
, so the first match is added to moduleData.TypesScratch
, while any other matches are added to moduleData.DuplicateTypes
:
Eventually this means that TypeMappingReleaseNativeAssemblyGenerator.WriteJavaMap()
writes the MetadataToken
of Class0<T>
into typemaps.arm64-v8a.s instead of the MetadataToken
of Class1
Version information
- Xamarin.Android SDK 10.3.0.80 (d16-6/0fe28fb)
- Java.Interop: xamarin/java.interop/d16-6@2cab35c
The issue also occurs when using the fixes from the candidate .vsix installer for #4656:
- Xamarin.Android SDK 10.4.100.6 (remotes/pull/4656/merge/5266fab)
- Java.Interop: xamarin/java.interop/master@377c4c7
This is expected because the changes in #4656 were only targeted for Debug configuration builds. (And indeed those fixes seemed to be effective for the DrawableTinting sample in the Debug configuration in my local environment.)
VS bug #1119273