Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test failure in TestBundleIntegerArrayList2 when the shared runtime is enabled #4596

Closed
pjcollins opened this issue Apr 21, 2020 · 7 comments · Fixed by #4656 or #4673
Closed

Test failure in TestBundleIntegerArrayList2 when the shared runtime is enabled #4596

pjcollins opened this issue Apr 21, 2020 · 7 comments · Fixed by #4656 or #4673
Assignees
Labels
Area: App Runtime Issues in `libmonodroid.so`. regression

Comments

@pjcollins
Copy link
Member

Steps to Reproduce

  1. Build commercial xamarin-android in the debug configuration
  2. Build and run the runtime suite:
bin/Debug/bin/xabuild /restore src/Mono.Android/Test/Mono.Android-Tests.csproj /p:AndroidUseSharedRuntime=True /t:AcquireAndroidTarget,Install,CheckAndRecordApkSizes,RunTestApks
  1. TestBundleIntegerArrayList2 fails:
04-21 14:52:22.677 18253 18271 E NUnitLite: Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`1[T] because Type.ContainsGenericParameters is true.
04-21 14:52:22.677 18253 18271 E NUnitLite:   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 <a71bc0650544428ea4f1cb0a371f7a80>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <a71bc0650544428ea4f1cb0a371f7a80>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters) [0x00000] in <a71bc0650544428ea4f1cb0a371f7a80>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) [0x0001b] in <1d456e9a51254e87a1ca3e16f71731f5>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType) [0x00111] in <1d456e9a51254e87a1ca3e16f71731f5>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type) [0x00023] in <1d456e9a51254e87a1ca3e16f71731f5>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) [0x00017] in <1d456e9a51254e87a1ca3e16f71731f5>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) [0x00000] in <1d456e9a51254e87a1ca3e16f71731f5>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at Android.OS.Bundle.Get (System.String key) [0x0003d] in <1d456e9a51254e87a1ca3e16f71731f5>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 () [0x00025] in <5daacb16ac9f4a9dab0d94f83afb3ab7>:0 
04-21 14:52:22.677 18253 18271 E NUnitLite:   at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
04-21 14:52:22.677 18253 18271 E NUnitLite:   at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0006a] in <a71bc0650544428ea4f1cb0a371f7a80>:0 

I tried dropping the test source into a regular dummy app and did not see the same crash however...

@pjcollins pjcollins added the Area: App Runtime Issues in `libmonodroid.so`. label Apr 21, 2020
@VincentDondain VincentDondain added this to the d16-7 milestone Apr 21, 2020
@pjcollins pjcollins modified the milestones: d16-7, d16-6 Apr 24, 2020
@pjcollins
Copy link
Member Author

pjcollins commented Apr 24, 2020

I've got a better reproduction for this and it's also affecting d16-6. You can hit this by installing and running https://github.com/xamarin/monodroid-samples/tree/master/android5.0/DrawableTinting on device in Debug mode.

The crash happens here - https://github.com/xamarin/monodroid-samples/blob/master/android5.0/DrawableTinting/DrawableTinting/DrawableTintingFragment.cs#L118

I've linked logcat output for the latest d16-6 results runtime test failure and the DrawableTinting sample crash.

@jonpryor
Copy link
Member

jonpryor commented Apr 27, 2020

grendello added a commit to grendello/xamarin-android that referenced this issue Apr 30, 2020
Fixes: dotnet#4596
Context: 7117414

7117414 made string lookup return into our type map support, for Debug
builds only, and with them the old problem of duplicate type names
returned as well - it is possible that a single Java type name will map
to a number of managed types and vice versa.  This is not a problem in
most cases, but whenever a Java type name maps to a generic managed
type (for instance "Android.Runtime.JavaList`1, Mono.Android"), the
code added in 7117414 runs into trouble:

    System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
       at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
       at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
       at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
       at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
       at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
       at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
       at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
       at Android.OS.Bundle.Get (System.String key)
       at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
       at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
       at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The reason this happens is due to the way the native code processes the
managed type name it obtained from the `Java -> managed` map.  Namely,
it uses Mono embedding API to return a `MonoType` instance corresponding
to the managed type name, then that `MonoType` instance is converted
into `MonoReflectionType*` which is returned to the managed code (it
corresponds to the `System.Type` instance there) and then an attempt to
instantiate this type is made in the usual way.  It works for
non-generic types, but whenever a generic type is processed in this way
it will result in us returning a `MonoReflectionType*` corresponding to
an **open** generic type which then results in the exception shown
above.

Given just the type name, the native runtime is unable to "close" the
generic type without information regarding the types of the generic
parameters needed to do it.  The solution, a workaround really, for now
is to look at the type name and return `null` to the managed code
whenever we see that the type name contains the "`" character, marking
it as a generic type.  The managed code will then proceed to look up the
type and instantiate it in the correct way.

In the future we need to find a better solution for this issue, but
doing so would require quite extensive changes to our current code.  The
solution implemented here is sufficient for now.
jonpryor added a commit that referenced this issue May 1, 2020
Fixes: #4596

Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update `EmbeddedAssemblies::binary_search()` so that instead of
returning the "first" entry that the binary search happens to land on,
probe *previous* entries in the type mappings to see if they *also*
contain the same key.  `binary_search()` can instead return the
*first entry* within the mapping, not just the first it happens to
land upon while binary searching.

This should allow for more *consistent* behaviors, ensuring that
Java-to-managed typemap lookup obtains a *non*-generic type, thus
avoiding the `MemberAccessException`.

Additionally, update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
jonpryor added a commit that referenced this issue May 1, 2020
Fixes: #4596

Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update `EmbeddedAssemblies::binary_search()` so that instead of
returning the "first" entry that the binary search happens to land on,
probe *previous* entries in the type mappings to see if they *also*
contain the same key.  `binary_search()` can instead return the
*first entry* within the mapping, not just the first it happens to
land upon while binary searching.

This should allow for more *consistent* behaviors, ensuring that
Java-to-managed typemap lookup obtains a *non*-generic type, thus
avoiding the `MemberAccessException`.

Additionally, update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
@brendanzagaeski
Copy link
Contributor

I've got a better reproduction for this and it's also affecting d16-6. You can hit this by installing and running https://github.com/xamarin/monodroid-samples/tree/master/android5.0/DrawableTinting on device in Debug mode.

Partly just for my own future reference, I'll record that setting $(AndroidLinkMode)=None in the Release configuration in the DrawableTinting sample produces the same MemberAccessException, so, as expected given the nature of the underlying issue, this issue can in theory also affect apps built in the Release configuration.

@grendello
Copy link
Contributor

The Release builds don't use strings with the managed types. Each Java type name is associated with exactly one managed type using MVID (managed assembly's module UUID) and the type token id. The same is true in reverse - a MVID:TOKEN_ID pair matches exactly one Java type name (we have code in place which handles Java type name duplicates by associating various MVID:TOKEN_ID pairs to the same type name). Therefore, binary search never has to deal with duplicates in the array and always the first type found when generating the type map is placed in the lookup array. None of the repros here triggered the isue in Release mode.

grendello added a commit to grendello/xamarin-android that referenced this issue May 6, 2020
Fixes: dotnet#4596
Context: 7117414

Do the heavy lifting on the build time instead of the run time.  Prefer
base types and always map all the duplicate entries to the **first**
entry encountered.
grendello added a commit to grendello/xamarin-android that referenced this issue May 6, 2020
Fixes: dotnet#4596
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks` so that
all the duplicate Java type names will point to the same managed type
name.  Additionally, make sure we select the managed type in the same
fashion the old typemap generator in `Java.Interop` worked - prefer base
types to the derived ones if the type is an interface or an abstract
class.  The effect of this change is that no matter which entry
`binary_search` ends up selecting it will always return the same managed
type name for all the aliased Java types.

Additionally, update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668

Do the heavy lifting on the build time instead of the run time.  Prefer
base types and always map all the duplicate entries to the **first**
entry encountered.
grendello added a commit to grendello/xamarin-android that referenced this issue May 6, 2020
Fixes: dotnet#4596
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks` so that
all the duplicate Java type names will point to the same managed type
name.  Additionally, make sure we select the managed type in the same
fashion the old typemap generator in `Java.Interop` worked - prefer base
types to the derived ones if the type is an interface or an abstract
class.  The effect of this change is that no matter which entry
`binary_search` ends up selecting it will always return the same managed
type name for all the aliased Java types.

Additionally, update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
grendello added a commit to grendello/xamarin-android that referenced this issue May 7, 2020
Fixes: dotnet#4596
Fixes: dotnet#4660
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186
Context: https://github.com/xamarin/java.interop/blob/010161d1ef6625b762429334f02e7b15e1f7caae/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L155

~~ Debug Mode ~~

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks` so that
all the duplicate Java type names will point to the same managed type
name.  Additionally, make sure we select the managed type in the same
fashion the old typemap generator in `Java.Interop` worked - prefer base
types to the derived ones if the type is an interface or an abstract
class.  The effect of this change is that no matter which entry
`binary_search` ends up selecting it will always return the same managed
type name for all the aliased Java types.

~~ Release mode ~~

Another issue introduced in ce2bc68 is that we no longer ignore
interface and generic types when generating the Java-to-managed maps.
This adversely affects the `Release` mode in which it is possible that
an attempt to instantiate an open generic type (or an interface) will
happen, leading to error similar to:

   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)
      at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
      at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
      at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
      at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
      at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
      at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
      at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
      at Com.Contoso.Javalibrary1.Class1.Create ()
      at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState)
      at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState)
      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)

Update typemap generation code to also ignore generic types and
interfaces when generating the Java to Managed map in `Release` mode. We
must not simply skip outputting entries for such types because we need
to maintain element count parity between java-to-managed and
managed-to-java lookup tables.  Therefore, the way we skip such types is
to output a type token ID of `0` instead of the actual one.  This will
cause the runtime code to fail to find a mapping, thus allowing the
managed code to deal with such a type properly.

Additionally, update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
grendello added a commit to grendello/xamarin-android that referenced this issue May 7, 2020
Fixes: dotnet#4596
Fixes: dotnet#4660
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186
Context: https://github.com/xamarin/java.interop/blob/010161d1ef6625b762429334f02e7b15e1f7caae/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L155

~~ Debug Mode ~~

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks` so that
all the duplicate Java type names will point to the same managed type
name.  Additionally, make sure we select the managed type in the same
fashion the old typemap generator in `Java.Interop` worked - prefer base
types to the derived ones if the type is an interface or an abstract
class.  The effect of this change is that no matter which entry
`binary_search` ends up selecting it will always return the same managed
type name for all the aliased Java types.

~~ Release mode ~~

Another issue introduced in ce2bc68 is that we no longer ignore
interface and generic types when generating the Java-to-managed maps.
This adversely affects the `Release` mode in which it is possible that
an attempt to instantiate an open generic type (or an interface) will
happen, leading to error similar to:

	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)
	    at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	    at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	    at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	    at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	    at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Com.Contoso.Javalibrary1.Class1.Create ()
	    at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState)
	    at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState)
	    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)

Update typemap generation code to also ignore generic types and
interfaces when generating the Java to Managed map in `Release` mode. We
must not simply skip outputting entries for such types because we need
to maintain element count parity between java-to-managed and
managed-to-java lookup tables.  Therefore, the way we skip such types is
to output a type token ID of `0` instead of the actual one.  This will
cause the runtime code to fail to find a mapping, thus allowing the
managed code to deal with such a type properly.

Additionally, update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
grendello added a commit to grendello/xamarin-android that referenced this issue May 7, 2020
Fixes: dotnet#4596
Fixes: dotnet#4660
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186
Context: https://github.com/xamarin/java.interop/blob/010161d1ef6625b762429334f02e7b15e1f7caae/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L155

~~ Debug Mode ~~

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks` so that
all the duplicate Java type names will point to the same managed type
name.  Additionally, make sure we select the managed type in the same
fashion the old typemap generator in `Java.Interop` worked - prefer base
types to the derived ones if the type is an interface or an abstract
class.  The effect of this change is that no matter which entry
`binary_search` ends up selecting it will always return the same managed
type name for all the aliased Java types.

~~ Release mode ~~

Another issue introduced in ce2bc68 is that we no longer ignore
interface and generic types when generating the Java-to-managed maps.
This adversely affects the `Release` mode in which it is possible that
an attempt to instantiate an open generic type (or an interface) will
happen, leading to error similar to:

	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)
	    at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	    at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	    at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	    at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	    at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Com.Contoso.Javalibrary1.Class1.Create ()
	    at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState)
	    at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState)
	    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)

Update typemap generation code to also ignore generic types and
interfaces when generating the Java to Managed map in `Release` mode. We
must not simply skip outputting entries for such types because we need
to maintain element count parity between java-to-managed and
managed-to-java lookup tables.  Therefore, the way we skip such types is
to output a type token ID of `0` instead of the actual one.  This will
cause the runtime code to fail to find a mapping, thus allowing the
managed code to deal with such a type properly.

~~ Test Updates ~~

Update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

Add a unit test for issue dotnet#4660 (by @brendanzagaeski)

It's very cute. :-)

We sort the Java-to-managed type name table, so it can be binary
searched to find the Managed type.

Additionally, the "preferred" managed type is the *first* type in
`monodis --typedef` output; the first type that we encounter when
going through all types in an assembly.

Brendan's cute way of provoking the bug is to add a new *generic* type
which will come *before* the "normally preferred" (and correct!) type.
Thus, even if/when binary search returns the first entry, that'll
still be the *wrong entry*, because that'll be a generic type!

Very cute.

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
grendello added a commit to grendello/xamarin-android that referenced this issue May 8, 2020
Fixes: dotnet#4596
Fixes: dotnet#4660
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186
Context: https://github.com/xamarin/java.interop/blob/010161d1ef6625b762429334f02e7b15e1f7caae/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L155

~~ Debug Mode ~~

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when  using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three* bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

  java/util/ArrayList
  Android.Runtime.JavaList, Mono.Android
  java/util/ArrayList
  Android.Runtime.JavaList`1, Mono.Android
  java/util/ArrayList
  Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks` so that
all the duplicate Java type names will point to the same managed type
name.  Additionally, make sure we select the managed type in the same
fashion the old typemap generator in `Java.Interop` worked - prefer base
types to the derived ones if the type is an interface or an abstract
class.  The effect of this change is that no matter which entry
`binary_search` ends up selecting it will always return the same managed
type name for all the aliased Java types.

~~ Release mode ~~

Another issue introduced in ce2bc68 is that we no longer ignore
interface and generic types when generating the Java-to-managed maps.
This adversely affects the `Release` mode in which it is possible that
an attempt to instantiate an open generic type (or an interface) will
happen, leading to error similar to:

	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)
	    at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	    at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	    at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	    at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	    at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Com.Contoso.Javalibrary1.Class1.Create ()
	    at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState)
	    at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState)
	    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)

Update typemap generation code to also ignore generic types and
interfaces when generating the Java to Managed map in `Release` mode. We
must not simply skip outputting entries for such types because we need
to maintain element count parity between java-to-managed and
managed-to-java lookup tables.  Therefore, the way we skip such types is
to output a type token ID of `0` instead of the actual one.  This will
cause the runtime code to fail to find a mapping, thus allowing the
managed code to deal with such a type properly.

~~ Test Updates ~~

Update `TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

Add a unit test for issue dotnet#4660 (by @brendanzagaeski)

It's very cute. :-)

We sort the Java-to-managed type name table, so it can be binary
searched to find the Managed type.

Additionally, the "preferred" managed type is the *first* type in
`monodis --typedef` output; the first type that we encounter when
going through all types in an assembly.

Brendan's cute way of provoking the bug is to add a new *generic* type
which will come *before* the "normally preferred" (and correct!) type.
Thus, even if/when binary search returns the first entry, that'll
still be the *wrong entry*, because that'll be a generic type!

Very cute.

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
jonpryor pushed a commit that referenced this issue May 8, 2020
Fixes: #4596
Fixes: #4660
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186
Context: https://github.com/xamarin/java.interop/blob/010161d1ef6625b762429334f02e7b15e1f7caae/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L155

~~ Debug Mode ~~

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three*
bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

	java/util/ArrayList
	Android.Runtime.JavaList, Mono.Android
	java/util/ArrayList
	Android.Runtime.JavaList`1, Mono.Android
	java/util/ArrayList
	Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks.dll` so
that all the duplicate Java type names will point to the same managed
type name.  Additionally, make sure we select the managed type in the
same fashion the old typemap generator in `Java.Interop` worked: prefer
base types to the derived ones if the type is an interface or an
abstract class.  The effect of this change is that no matter which
entry `EmbeddedAssemblies::binary_search()` ends up selecting it will
always return the same managed type name for all aliased Java types.


~~ Release config apps ~~

Another issue introduced in ce2bc68 is that we no longer ignore
interface and generic types when generating the Java-to-managed maps.
This adversely affects the `Release` mode in which it is possible that
an attempt to instantiate an open generic type (or an interface) will
happen, leading to error similar to:

	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)
	    at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	    at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	    at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	    at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	    at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Com.Contoso.Javalibrary1.Class1.Create ()
	    at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState)
	    at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState)
	    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)

Update typemap generation code to also ignore generic types and
interfaces when generating the Java to Managed map in `Release` mode.
We must not simply skip outputting entries for such types because we
need to maintain element count parity between java-to-managed and
managed-to-java lookup tables.  Therefore, the way we skip such types
is to output a type token ID of `0` instead of the actual one.  This
will cause the runtime code to fail to find a mapping, thus allowing
the managed code to deal with such a type properly.


~~ Test Updates ~~

Update `BundleTest.TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

Add a unit test for the Release config app bug in Issue #4660; thanks
to @brendanzagaeski.  It works by provoking the binary search bug by
"ensuring" that a *generic* type comes *before* the "normally
preferred" *non*-generic type.  Thus, even if/when binary search
returns the first entry, that would still be the *wrong entry*,
because that'll be a generic type!

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
jonpryor pushed a commit that referenced this issue May 8, 2020
Fixes: #4596
Fixes: #4660
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186
Context: https://github.com/xamarin/java.interop/blob/010161d1ef6625b762429334f02e7b15e1f7caae/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L155

~~ Debug Mode ~~

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three*
bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

	java/util/ArrayList
	Android.Runtime.JavaList, Mono.Android
	java/util/ArrayList
	Android.Runtime.JavaList`1, Mono.Android
	java/util/ArrayList
	Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks.dll` so
that all the duplicate Java type names will point to the same managed
type name.  Additionally, make sure we select the managed type in the
same fashion the old typemap generator in `Java.Interop` worked: prefer
base types to the derived ones if the type is an interface or an
abstract class.  The effect of this change is that no matter which
entry `EmbeddedAssemblies::binary_search()` ends up selecting it will
always return the same managed type name for all aliased Java types.


~~ Release config apps ~~

Another issue introduced in ce2bc68 is that we no longer ignore
interface and generic types when generating the Java-to-managed maps.
This adversely affects the `Release` mode in which it is possible that
an attempt to instantiate an open generic type (or an interface) will
happen, leading to error similar to:

	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)
	    at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	    at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	    at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	    at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	    at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Com.Contoso.Javalibrary1.Class1.Create ()
	    at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState)
	    at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState)
	    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)

Update typemap generation code to also ignore generic types and
interfaces when generating the Java to Managed map in `Release` mode.
We must not simply skip outputting entries for such types because we
need to maintain element count parity between java-to-managed and
managed-to-java lookup tables.  Therefore, the way we skip such types
is to output a type token ID of `0` instead of the actual one.  This
will cause the runtime code to fail to find a mapping, thus allowing
the managed code to deal with such a type properly.


~~ Test Updates ~~

Update `BundleTest.TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

Add a unit test for the Release config app bug in Issue #4660; thanks
to @brendanzagaeski.  It works by provoking the binary search bug by
"ensuring" that a *generic* type comes *before* the "normally
preferred" *non*-generic type.  Thus, even if/when binary search
returns the first entry, that would still be the *wrong entry*,
because that'll be a generic type!

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
jonpryor pushed a commit that referenced this issue May 8, 2020
Fixes: #4596
Fixes: #4660
Context: xamarin/monodroid@192b1f1
Context: https://github.com/xamarin/java.interop/blob/fc18c54b2ccf14f444fadac0a1e7e81f837cc470/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L149-L186
Context: https://github.com/xamarin/java.interop/blob/010161d1ef6625b762429334f02e7b15e1f7caae/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L155

~~ Debug Mode ~~

In some environments, `BundleTest.TestBundleIntegerArrayList2()` fails
when using the commercial shared runtime:

	Test 'Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2' failed: System.MemberAccessException : Cannot create an instance of Android.Runtime.JavaList`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)
	  at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	  at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	  at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	  at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	  at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	  at Android.OS.Bundle.Get (System.String key)
	  at Xamarin.Android.RuntimeTests.BundleTest.TestBundleIntegerArrayList2 ()
	  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.InternalInvoke(System.Reflection.RuntimeMethodInfo,object,object[],System.Exception&)
	  at System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)

The problem appears to be rooted in ce2bc68.  In a pre-ce2bc689 world,
there were two separate sets of "typemap" files that the application
could use:

  * Java-to-managed mappings, in `typemap.jm`
  * Managed-to-Java mappings, in `typemap.mj`.

These files did *not* need to have the same number of entries!

	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.jm
	% unzip /Library/Frameworks/Xamarin.Android.framework/Versions/10.2.0.100/lib/xamarin.android/xbuild/Xamarin/Android/Mono.Android.DebugRuntime-debug.apk typemap.mj
	% strings typemap.jm | wc -l
	   10318
	% strings typemap.mj | wc -l
	   11956

The reason why they have a different number of entries is *aliasing*:
there can be *multiple* bindings for a given Java type.  The
managed-to-Java mappings can contain *all* of them; the
Java-to-managed mapping *must* pick Only One.

For example, [`java.util.ArrayList`][0] contains (at least?) *three*
bindings:

  * [`Android.Runtime.JavaList`][1]
  * [`Android.Runtime.JavaList<T>`][2]
  * `Java.Util.ArrayList` (generated at build time)

In a pre-ce2bc689 world, this was "fine": we'd binary search each file
*separately* to find type mappings.

This changed in ce2bc68, as the typemap information was merged into a
*single* array in order to de-duplicate information.  This reduced
`.apk` size.

An unanticipated result of this is that the Java-to-managed mappings
can now contain *duplicate* keys, "as if" the original `typemap.jm`
had the contents:

	java/util/ArrayList
	Android.Runtime.JavaList, Mono.Android
	java/util/ArrayList
	Android.Runtime.JavaList`1, Mono.Android
	java/util/ArrayList
	Java.Util.ArrayLlist, Mono.Android

Whereas pre-ce2bc689 there would have only been the first entry.

"Sometimes" this duplication is "fine": the typemap search
"Just happens" to return the first entry, or the 3rd entry, and apps
continue to work as intended.

"Sometimes" it isn't: the typemap binary search finds the 2nd entry,
which is a generic type.  This results in attempting to instantiate a
generic type *without appropriate type parameters*, which results in
the aforementioned `MemberAccessException`.

Update typemap generation code in `Xamarin.Android.Build.Tasks.dll` so
that all the duplicate Java type names will point to the same managed
type name.  Additionally, make sure we select the managed type in the
same fashion the old typemap generator in `Java.Interop` worked: prefer
base types to the derived ones if the type is an interface or an
abstract class.  The effect of this change is that no matter which
entry `EmbeddedAssemblies::binary_search()` ends up selecting it will
always return the same managed type name for all aliased Java types.


~~ Release config apps ~~

Another issue introduced in ce2bc68 is that we no longer ignore
interface and generic types when generating the Java-to-managed maps.
This adversely affects the `Release` mode in which it is possible that
an attempt to instantiate an open generic type (or an interface) will
happen, leading to error similar to:

	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)
	    at System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
	    at System.Reflection.ConstructorInfo.Invoke (System.Object[] parameters)
	    at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType)
	    at Java.Lang.Object.GetObject (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type type)
	    at Java.Lang.Object._GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Java.Lang.Object.GetObject[T] (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer)
	    at Com.Contoso.Javalibrary1.Class1.Create ()
	    at AndroidSingleViewApp1.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState)
	    at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState)
	    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)

Update typemap generation code to also ignore generic types and
interfaces when generating the Java to Managed map in `Release` mode.
We must not simply skip outputting entries for such types because we
need to maintain element count parity between java-to-managed and
managed-to-java lookup tables.  Therefore, the way we skip such types
is to output a type token ID of `0` instead of the actual one.  This
will cause the runtime code to fail to find a mapping, thus allowing
the managed code to deal with such a type properly.


~~ Test Updates ~~

Update `BundleTest.TestBundleIntegerArrayList2()` so that it asserts
the runtime *type* of `obj` returned, asserting that it is in fact a
`JavaList` and not e.g. `Java.Util.ArrayList` or something.
(The linker could otherwise "change" things, and this assertion will
ensure that `JavaList` won't be linked away…)

Add a unit test for the Release config app bug in Issue #4660; thanks
to @brendanzagaeski.  It works by provoking the binary search bug by
"ensuring" that a *generic* type comes *before* the "normally
preferred" *non*-generic type.  Thus, even if/when binary search
returns the first entry, that would still be the *wrong entry*,
because that'll be a generic type!

[0]: https://developer.android.com/reference/java/util/ArrayList
[1]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L11-L13
[2]: https://github.com/xamarin/xamarin-android/blob/61f09bf2ef0c8f09550e2d77eb97f417432b315b/src/Mono.Android/Android.Runtime/JavaList.cs#L667-L668
@pjcollins
Copy link
Member Author

@grendello I'm seeing a new startup crash with the DrawableTinting test case with this patch applied to d16-6: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

I'm worried about other potential fallout/risk on d16-6 with changes coming this late (unfortunately in part due to detection of this issue coming late in the cycle). Do we have a sane way to revert to d16-5 behavior here for the shorter time frame and look to address this more properly in d16-7 or d16-8? I understand this would carry a performance hit but I think it would be preferable to limit the scope of change in d16-6 at this point if possible.

grendello added a commit to grendello/xamarin-android that referenced this issue May 11, 2020
Fixes: dotnet#4596
Context: a017561
Context: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

A missing parameter in a call to `log_debug` added in a017561 may lead
to a segfault when `assembly` log category and `debug` log level are
enabled:

		F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3 in tid 922 (DrawableTinting), pid 922 (DrawableTinting)
		I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
		I /system/bin/tombstoned: received crash request for pid 922
		I crash_dump64: performing dump of process 922 (target tid = 922)
		F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
		F DEBUG   : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:9/PSR1.180720.012/4923214:userdebug/test-keys'
		F DEBUG   : Revision: '0'
		F DEBUG   : ABI: 'x86_64'
		F DEBUG   : pid: 922, tid: 922, name: DrawableTinting  >>> com.xamarin.DrawableTinting <<<
		F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3
		F DEBUG   : Cause: null pointer dereference
		F DEBUG   :     rax 0000000000000000  rbx 00007ffed3c283c0  rcx 0000000000000003  rdx 0000000000000002
		F DEBUG   :     r8  00007ffed3c283c0  r9  00000000ffffffff  r10 00007ffed3c283d0  r11 00007ffed3c28824
		F DEBUG   :     r12 00007c88774a2f17  r13 00000000ffffffff  r14 0000000000000000  r15 00007ffed3c283d0
		F DEBUG   :     rdi 0000000000000003  rsi 00007ffed3c283bb
		F DEBUG   :     rbp 00007ffed3c28f18  rsp 00007ffed3c28288  rip 00007c890f860761
		F DEBUG   :
		F DEBUG   : backtrace:
		F DEBUG   :     #00 pc 0000000000020761  /system/lib64/libc.so (strlen+17)
		F DEBUG   :     #1 pc 000000000006e761  /system/lib64/libc.so (__vfprintf+5953)
		F DEBUG   :     #2 pc 000000000008df5d  /system/lib64/libc.so (vsnprintf+189)
		F DEBUG   :     #3 pc 0000000000007b60  /system/lib64/liblog.so (__android_log_vprint+64)
		F DEBUG   :     dotnet#4 pc 000000000001350c  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (log_debug_nocheck(_LogCategories, char const*, ...)+204)
		F DEBUG   :     dotnet#5 pc 000000000000de6a  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(char const*)+538)
		F DEBUG   :     dotnet#6 pc 000000000000df13  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(_MonoString*)+99)
		F DEBUG   :     dotnet#7 pc 00000000000d57f8  <anonymous:0000000042d04000>

Add the missing parameter to prevent the `SIGSEGV` from happening.
jonpryor pushed a commit that referenced this issue May 11, 2020
…4673)

Fixes: #4596
Context: a017561
Context: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

A missing parameter in a call to `log_debug` added iFixes: #4596
Context: a017561
Context: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

A missing parameter in a call to `log_debug()` added in a017561 may
lead to a segfault when `assembly` log category and `debug` log level
are enabled:

	F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3 in tid 922 (DrawableTinting), pid 922 (DrawableTinting)
	I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
	I /system/bin/tombstoned: received crash request for pid 922
	I crash_dump64: performing dump of process 922 (target tid = 922)
	F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
	F DEBUG   : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:9/PSR1.180720.012/4923214:userdebug/test-keys'
	F DEBUG   : Revision: '0'
	F DEBUG   : ABI: 'x86_64'
	F DEBUG   : pid: 922, tid: 922, name: DrawableTinting  >>> com.xamarin.DrawableTinting <<<
	F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3
	F DEBUG   : Cause: null pointer dereference
	F DEBUG   :     rax 0000000000000000  rbx 00007ffed3c283c0  rcx 0000000000000003  rdx 0000000000000002
	F DEBUG   :     r8  00007ffed3c283c0  r9  00000000ffffffff  r10 00007ffed3c283d0  r11 00007ffed3c28824
	F DEBUG   :     r12 00007c88774a2f17  r13 00000000ffffffff  r14 0000000000000000  r15 00007ffed3c283d0
	F DEBUG   :     rdi 0000000000000003  rsi 00007ffed3c283bb
	F DEBUG   :     rbp 00007ffed3c28f18  rsp 00007ffed3c28288  rip 00007c890f860761
	F DEBUG   :
	F DEBUG   : backtrace:
	F DEBUG   :     #00 pc 0000000000020761  /system/lib64/libc.so (strlen+17)
	F DEBUG   :     #1 pc 000000000006e761  /system/lib64/libc.so (__vfprintf+5953)
	F DEBUG   :     #2 pc 000000000008df5d  /system/lib64/libc.so (vsnprintf+189)
	F DEBUG   :     #3 pc 0000000000007b60  /system/lib64/liblog.so (__android_log_vprint+64)
	F DEBUG   :     #4 pc 000000000001350c  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (log_debug_nocheck(_LogCategories, char const*, ...)+204)
	F DEBUG   :     #5 pc 000000000000de6a  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(char const*)+538)
	F DEBUG   :     #6 pc 000000000000df13  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(_MonoString*)+99)
	F DEBUG   :     #7 pc 00000000000d57f8  <anonymous:0000000042d04000>

Add the missing parameter to prevent the `SIGSEGV` from happening.n a017561 may lead
to a segfault when `assembly` log category and `debug` log level are
enabled:

		F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3 in tid 922 (DrawableTinting), pid 922 (DrawableTinting)
		I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
		I /system/bin/tombstoned: received crash request for pid 922
		I crash_dump64: performing dump of process 922 (target tid = 922)
		F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
		F DEBUG   : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:9/PSR1.180720.012/4923214:userdebug/test-keys'
		F DEBUG   : Revision: '0'
		F DEBUG   : ABI: 'x86_64'
		F DEBUG   : pid: 922, tid: 922, name: DrawableTinting  >>> com.xamarin.DrawableTinting <<<
		F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3
		F DEBUG   : Cause: null pointer dereference
		F DEBUG   :     rax 0000000000000000  rbx 00007ffed3c283c0  rcx 0000000000000003  rdx 0000000000000002
		F DEBUG   :     r8  00007ffed3c283c0  r9  00000000ffffffff  r10 00007ffed3c283d0  r11 00007ffed3c28824
		F DEBUG   :     r12 00007c88774a2f17  r13 00000000ffffffff  r14 0000000000000000  r15 00007ffed3c283d0
		F DEBUG   :     rdi 0000000000000003  rsi 00007ffed3c283bb
		F DEBUG   :     rbp 00007ffed3c28f18  rsp 00007ffed3c28288  rip 00007c890f860761
		F DEBUG   :
		F DEBUG   : backtrace:
		F DEBUG   :     #00 pc 0000000000020761  /system/lib64/libc.so (strlen+17)
		F DEBUG   :     #1 pc 000000000006e761  /system/lib64/libc.so (__vfprintf+5953)
		F DEBUG   :     #2 pc 000000000008df5d  /system/lib64/libc.so (vsnprintf+189)
		F DEBUG   :     #3 pc 0000000000007b60  /system/lib64/liblog.so (__android_log_vprint+64)
		F DEBUG   :     #4 pc 000000000001350c  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (log_debug_nocheck(_LogCategories, char const*, ...)+204)
		F DEBUG   :     #5 pc 000000000000de6a  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(char const*)+538)
		F DEBUG   :     #6 pc 000000000000df13  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(_MonoString*)+99)
		F DEBUG   :     #7 pc 00000000000d57f8  <anonymous:0000000042d04000>

Add the missing parameter to prevent the `SIGSEGV` from happening.
jonpryor pushed a commit that referenced this issue May 12, 2020
…4673)

Fixes: #4596
Context: a017561
Context: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

A missing parameter in a call to `log_debug` added iFixes: #4596
Context: a017561
Context: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

A missing parameter in a call to `log_debug()` added in a017561 may
lead to a segfault when `assembly` log category and `debug` log level
are enabled:

	F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3 in tid 922 (DrawableTinting), pid 922 (DrawableTinting)
	I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
	I /system/bin/tombstoned: received crash request for pid 922
	I crash_dump64: performing dump of process 922 (target tid = 922)
	F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
	F DEBUG   : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:9/PSR1.180720.012/4923214:userdebug/test-keys'
	F DEBUG   : Revision: '0'
	F DEBUG   : ABI: 'x86_64'
	F DEBUG   : pid: 922, tid: 922, name: DrawableTinting  >>> com.xamarin.DrawableTinting <<<
	F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3
	F DEBUG   : Cause: null pointer dereference
	F DEBUG   :     rax 0000000000000000  rbx 00007ffed3c283c0  rcx 0000000000000003  rdx 0000000000000002
	F DEBUG   :     r8  00007ffed3c283c0  r9  00000000ffffffff  r10 00007ffed3c283d0  r11 00007ffed3c28824
	F DEBUG   :     r12 00007c88774a2f17  r13 00000000ffffffff  r14 0000000000000000  r15 00007ffed3c283d0
	F DEBUG   :     rdi 0000000000000003  rsi 00007ffed3c283bb
	F DEBUG   :     rbp 00007ffed3c28f18  rsp 00007ffed3c28288  rip 00007c890f860761
	F DEBUG   :
	F DEBUG   : backtrace:
	F DEBUG   :     #00 pc 0000000000020761  /system/lib64/libc.so (strlen+17)
	F DEBUG   :     #1 pc 000000000006e761  /system/lib64/libc.so (__vfprintf+5953)
	F DEBUG   :     #2 pc 000000000008df5d  /system/lib64/libc.so (vsnprintf+189)
	F DEBUG   :     #3 pc 0000000000007b60  /system/lib64/liblog.so (__android_log_vprint+64)
	F DEBUG   :     #4 pc 000000000001350c  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (log_debug_nocheck(_LogCategories, char const*, ...)+204)
	F DEBUG   :     #5 pc 000000000000de6a  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(char const*)+538)
	F DEBUG   :     #6 pc 000000000000df13  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(_MonoString*)+99)
	F DEBUG   :     #7 pc 00000000000d57f8  <anonymous:0000000042d04000>

Add the missing parameter to prevent the `SIGSEGV` from happening.n a017561 may lead
to a segfault when `assembly` log category and `debug` log level are
enabled:

		F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3 in tid 922 (DrawableTinting), pid 922 (DrawableTinting)
		I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
		I /system/bin/tombstoned: received crash request for pid 922
		I crash_dump64: performing dump of process 922 (target tid = 922)
		F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
		F DEBUG   : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:9/PSR1.180720.012/4923214:userdebug/test-keys'
		F DEBUG   : Revision: '0'
		F DEBUG   : ABI: 'x86_64'
		F DEBUG   : pid: 922, tid: 922, name: DrawableTinting  >>> com.xamarin.DrawableTinting <<<
		F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3
		F DEBUG   : Cause: null pointer dereference
		F DEBUG   :     rax 0000000000000000  rbx 00007ffed3c283c0  rcx 0000000000000003  rdx 0000000000000002
		F DEBUG   :     r8  00007ffed3c283c0  r9  00000000ffffffff  r10 00007ffed3c283d0  r11 00007ffed3c28824
		F DEBUG   :     r12 00007c88774a2f17  r13 00000000ffffffff  r14 0000000000000000  r15 00007ffed3c283d0
		F DEBUG   :     rdi 0000000000000003  rsi 00007ffed3c283bb
		F DEBUG   :     rbp 00007ffed3c28f18  rsp 00007ffed3c28288  rip 00007c890f860761
		F DEBUG   :
		F DEBUG   : backtrace:
		F DEBUG   :     #00 pc 0000000000020761  /system/lib64/libc.so (strlen+17)
		F DEBUG   :     #1 pc 000000000006e761  /system/lib64/libc.so (__vfprintf+5953)
		F DEBUG   :     #2 pc 000000000008df5d  /system/lib64/libc.so (vsnprintf+189)
		F DEBUG   :     #3 pc 0000000000007b60  /system/lib64/liblog.so (__android_log_vprint+64)
		F DEBUG   :     #4 pc 000000000001350c  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (log_debug_nocheck(_LogCategories, char const*, ...)+204)
		F DEBUG   :     #5 pc 000000000000de6a  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(char const*)+538)
		F DEBUG   :     #6 pc 000000000000df13  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(_MonoString*)+99)
		F DEBUG   :     #7 pc 00000000000d57f8  <anonymous:0000000042d04000>

Add the missing parameter to prevent the `SIGSEGV` from happening.
jonpryor pushed a commit that referenced this issue May 12, 2020
…4673)

Fixes: #4596
Context: a017561
Context: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

A missing parameter in a call to `log_debug` added iFixes: #4596
Context: a017561
Context: https://gist.github.com/pjcollins/87762e81f1f3c7e8b821356e4612eecf

A missing parameter in a call to `log_debug()` added in a017561 may
lead to a segfault when `assembly` log category and `debug` log level
are enabled:

	F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3 in tid 922 (DrawableTinting), pid 922 (DrawableTinting)
	I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
	I /system/bin/tombstoned: received crash request for pid 922
	I crash_dump64: performing dump of process 922 (target tid = 922)
	F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
	F DEBUG   : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:9/PSR1.180720.012/4923214:userdebug/test-keys'
	F DEBUG   : Revision: '0'
	F DEBUG   : ABI: 'x86_64'
	F DEBUG   : pid: 922, tid: 922, name: DrawableTinting  >>> com.xamarin.DrawableTinting <<<
	F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3
	F DEBUG   : Cause: null pointer dereference
	F DEBUG   :     rax 0000000000000000  rbx 00007ffed3c283c0  rcx 0000000000000003  rdx 0000000000000002
	F DEBUG   :     r8  00007ffed3c283c0  r9  00000000ffffffff  r10 00007ffed3c283d0  r11 00007ffed3c28824
	F DEBUG   :     r12 00007c88774a2f17  r13 00000000ffffffff  r14 0000000000000000  r15 00007ffed3c283d0
	F DEBUG   :     rdi 0000000000000003  rsi 00007ffed3c283bb
	F DEBUG   :     rbp 00007ffed3c28f18  rsp 00007ffed3c28288  rip 00007c890f860761
	F DEBUG   :
	F DEBUG   : backtrace:
	F DEBUG   :     #00 pc 0000000000020761  /system/lib64/libc.so (strlen+17)
	F DEBUG   :     #1 pc 000000000006e761  /system/lib64/libc.so (__vfprintf+5953)
	F DEBUG   :     #2 pc 000000000008df5d  /system/lib64/libc.so (vsnprintf+189)
	F DEBUG   :     #3 pc 0000000000007b60  /system/lib64/liblog.so (__android_log_vprint+64)
	F DEBUG   :     #4 pc 000000000001350c  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (log_debug_nocheck(_LogCategories, char const*, ...)+204)
	F DEBUG   :     #5 pc 000000000000de6a  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(char const*)+538)
	F DEBUG   :     #6 pc 000000000000df13  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(_MonoString*)+99)
	F DEBUG   :     #7 pc 00000000000d57f8  <anonymous:0000000042d04000>

Add the missing parameter to prevent the `SIGSEGV` from happening.n a017561 may lead
to a segfault when `assembly` log category and `debug` log level are
enabled:

		F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3 in tid 922 (DrawableTinting), pid 922 (DrawableTinting)
		I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
		I /system/bin/tombstoned: received crash request for pid 922
		I crash_dump64: performing dump of process 922 (target tid = 922)
		F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
		F DEBUG   : Build fingerprint: 'Android/sdk_phone_x86_64/generic_x86_64:9/PSR1.180720.012/4923214:userdebug/test-keys'
		F DEBUG   : Revision: '0'
		F DEBUG   : ABI: 'x86_64'
		F DEBUG   : pid: 922, tid: 922, name: DrawableTinting  >>> com.xamarin.DrawableTinting <<<
		F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3
		F DEBUG   : Cause: null pointer dereference
		F DEBUG   :     rax 0000000000000000  rbx 00007ffed3c283c0  rcx 0000000000000003  rdx 0000000000000002
		F DEBUG   :     r8  00007ffed3c283c0  r9  00000000ffffffff  r10 00007ffed3c283d0  r11 00007ffed3c28824
		F DEBUG   :     r12 00007c88774a2f17  r13 00000000ffffffff  r14 0000000000000000  r15 00007ffed3c283d0
		F DEBUG   :     rdi 0000000000000003  rsi 00007ffed3c283bb
		F DEBUG   :     rbp 00007ffed3c28f18  rsp 00007ffed3c28288  rip 00007c890f860761
		F DEBUG   :
		F DEBUG   : backtrace:
		F DEBUG   :     #00 pc 0000000000020761  /system/lib64/libc.so (strlen+17)
		F DEBUG   :     #1 pc 000000000006e761  /system/lib64/libc.so (__vfprintf+5953)
		F DEBUG   :     #2 pc 000000000008df5d  /system/lib64/libc.so (vsnprintf+189)
		F DEBUG   :     #3 pc 0000000000007b60  /system/lib64/liblog.so (__android_log_vprint+64)
		F DEBUG   :     #4 pc 000000000001350c  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (log_debug_nocheck(_LogCategories, char const*, ...)+204)
		F DEBUG   :     #5 pc 000000000000de6a  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(char const*)+538)
		F DEBUG   :     #6 pc 000000000000df13  /data/app/com.xamarin.DrawableTinting-zvchh4ya_DW11GfpEPFICw==/lib/x86_64/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_java_to_managed(_MonoString*)+99)
		F DEBUG   :     #7 pc 00000000000d57f8  <anonymous:0000000042d04000>

Add the missing parameter to prevent the `SIGSEGV` from happening.
@brendanzagaeski
Copy link
Contributor

Release status update

A Preview version of Xamarin.Android has now been published on macOS that includes the fix for this item.

The fix is not yet available on Windows. I will update this item again when a version with the fix is available on Windows.

Fix included in Xamarin.Android 10.3.1.0.

Fix included on macOS in Visual Studio 2019 for Mac version 8.6 Preview 6. To try the Preview version that includes the fix, check for the latest updates on the Preview updater channel.

Fix not yet available on Windows.

@brendanzagaeski
Copy link
Contributor

Release status update

A new Release version of Xamarin.Android has now been published on both Windows and macOS that includes the fix for this item.

Fix included in Xamarin.Android 10.3.1.0.

Fix included on Windows in Visual Studio 2019 version 16.6. To get the new version that includes the fix, check for the latest updates or install the latest version from https://visualstudio.microsoft.com/downloads/.

Fix included on macOS in Visual Studio 2019 for Mac version 8.6. To get the new version that includes the fix, check for the latest updates on the Stable updater channel.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.