Closed tipa closed 4 hours ago
I have the exact same issue. I've tried many variations, including a clean MAUI project running .NET 9 (full version, not pre-release).
Repro Exception
System.ArgumentException: Could not determine Java type corresponding to `AndroidX.Media3.ExoPlayer.IExoPlayerInvoker, Xamarin.AndroidX.Media3.ExoPlayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null`. (Parameter 'targetType')
at Java.Interop.TypeManager.CreateInstance(IntPtr handle, JniHandleOwnership transfer, Type targetType) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Interop/TypeManager.cs:line 323
at Java.Lang.Object.GetObject(IntPtr handle, JniHandleOwnership transfer, Type type) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Object.cs:line 302
at Java.Lang.Object._GetObject[IExoPlayer](IntPtr handle, JniHandleOwnership transfer) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Object.cs:line 288
at Java.Lang.Object.GetObject[IExoPlayer](IntPtr handle, JniHandleOwnership transfer) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Object.cs:line 280
at AndroidX.Media3.ExoPlayer.ExoPlayerBuilder.Build() in D:\a\_work\1\s\generated\androidx.media3.media3-exoplayer\obj\Release\net8.0-android\generated\src\AndroidX.Media3.ExoPlayer.IExoPlayer.cs:line 749
at media3.MainActivity.OnCreate(Bundle savedInstanceState) in /Users/moljac/Downloads/1036/media3/MainActivity.cs:line 16
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net9.0/android-35/mcw/Android.App.Activity.cs:line 3196
at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_V(_JniMarshal_PPL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 121
Here is an example of how to use media 3 with Maui. https://github.com/CommunityToolkit/Maui/pull/2076
var Player = new ExoPlayerBuilder(Platform.AppContext).Build() ?? throw new InvalidOperationException("Player cannot be null");
Above is how you create an new instance of the player
@ne0rrmatrix Have you tested this with .NET 9? I cannot get it working, just get the exception.
I have tested against dotnet 8 over the last few months. I am currently unable to test using either dotnet 8 or 9 and can't provide any feedback. After updating to dotnet 9 I cannot build anything. Once I get my mac's and pc's working with new dotnet I will see if any changes are needed.
Let me create repro sample for both net9.0
and net8.0
, so we can narrow it down.
Repro:
dotnet build net8.0/media3/media3.csproj -t:run -f:net8.0-android
OK!
dotnet build net9.0/media3/media3.csproj -t:run -f:net9.0-android
Crashes!!!
SDK
version needs to be set for dotnet 9.
Example:
{
"sdk":
{
"version": "9.0.100",
"rollForward": "patch"
},
"msbuild-sdks":
{
"MSBuild.Sdk.Extras": "3.0.44",
"Microsoft.Build.Traversal": "4.1.0",
"Microsoft.Build.NoTargets": "3.7.56",
"Xamarin.Legacy.Sdk": "0.2.0-alpha4"
}
}
Sample builds fine in Debug or Release mode when using current 9.0 version of dotnet from VS 2022 install.
edit: Sample build fine but does crash when app loads.
Sample builds fine in Debug or Release mode when using current 9.0 version of dotnet from VS 2022 install.
Yes. Builds fine, but crashes during running.
I believe that this was broken by: https://github.com/dotnet/android/commit/35f41dcc7cf5eb65dc12d7c0a3421e67c2bdb6d6
What I don't understand is why this wasn't caught by existing unit tests, e.g. https://github.com/dotnet/android/blob/70948d5eaa72091389940fdd5a0eb828c85bdd60/tests/Mono.Android-Tests/Java.Interop/JavaObjectExtensionsTests.cs#L38
@ne0rrmatrix
Does your app crash during running [loading]?
Just to be certain
App crashes after launching activity. It also only crashes when exoplayer build() instruction is executed
To be specific it crashes only when executing Build()
. If I run
var player = new ExoplayerBuilder(); // App does not crash. Return type is `ExoplayerBuilder`
player.Build(); // App crashes on this line. Return type is `IExoPlayer`
@ne0rrmatrix
Thanks a lot. Did you use repro sample provided in this issue?
Just asking, so other can use it for debugging.
thx
Yes I tried the sample app. It has exact same behavior. I also tested by modifying it like above to try and test if ExoPlayerBuilder
was working. It is working for that class. It is only the Build()
method that causes the crash.
Moving this to dotnet/android
for better visibility/tracking, as initial investigation appears to be a .NET 9 regression in Java.Interop
.
@jonpryor wrote:
What I don't understand is why this wasn't caught by existing unit tests, e.g. https://github.com/dotnet/android/blob/70948d5eaa72091389940fdd5a0eb828c85bdd60/tests/Mono.Android-Tests/Java.Interop/JavaObjectExtensionsTests.cs#L38
The answer is that before we try to do anything with *Invoker
types, we first try to use an existing binding for the runtime type:
https://github.com/dotnet/android/blob/4559426e2ab367e6b153363e0059f128e225f70d/src/Mono.Android/Java.Interop/TypeManager.cs#L246-L264
Because the runtime type is java.lang.Integer
, which is bound, we never actually hit the *Invoker
codepath.
(The test wasn't testing what I thought it was testing!)
For me, media3.zip works on .NET 9 when you build in Release configuration.
I can confirm it works in Release mode in .NET 9. It does not work in Debug mode though.
…which brings us to the question: What's Happening™?
Answer: type maps. (Borderline "duh.") Which differ in structure and content between Debug and Release builds.
For reasons I'm still digging into, the Debug config type maps also differ between Mono.Android.dll
and other assemblies. The type map for Mono.Android.dll
contains duplicate entries for *Invoker
types, e.g. from obj/Debug/net9.0-android/android/typemaps.arm64-v8a.ll
:
@.TypeMapEntry.17434_from = private unnamed_addr constant [47 x i8] c"Java.Util.Functions.IIntSupplier, Mono.Android\00", align 1
@.TypeMapEntry.17435_to = private unnamed_addr constant [31 x i8] c"java/util/function/IntSupplier\00", align 1
@.TypeMapEntry.17436_from = private unnamed_addr constant [54 x i8] c"Java.Util.Functions.IIntSupplierInvoker, Mono.Android\00", align 1
…
%struct.TypeMapEntry {
ptr @.TypeMapEntry.17434_from, ; char* from
ptr @.TypeMapEntry.17435_to; char* to
}, ; 9766
%struct.TypeMapEntry {
ptr @.TypeMapEntry.17436_from, ; char* from
ptr @.TypeMapEntry.17435_to; char* to
}, ; 9767
It does not contain *Invoker
entries for other assemblies:
@.TypeMapEntry.13525_from = private unnamed_addr constant [72 x i8] c"AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer\00", align 1
@.TypeMapEntry.13526_to = private unnamed_addr constant [36 x i8] c"androidx/media3/exoplayer/ExoPlayer\00", align 1
# no entry for IExoPlayerInvoker
though oddly the TypeMapEntry
array does have a duplicate! With the same from
and to
values:
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13525_from, ; char* from
ptr @.TypeMapEntry.13526_to; char* to
}, ; 7491
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13525_from, ; char* from
ptr @.TypeMapEntry.13526_to; char* to
}, ; 7492
Open Questions:
Mono.Android.dll
get "duplicates" for *Invoker
types while non-Mono.Android.dll
assemblies don't?(Building upon (2) and (3)): what's the correct fix?
Update type maps so that we reliably have duplicates?
Update type maps so they reliably don't have duplicates, update TypeManager.CreateInstance()
to appropriately deal with this (do type map lookup before determining Invoker
type)
Leave type maps alone, update TypeManager.CreateInstance()
to appropriately deal with this (do type map lookup before determining Invoker
type)
Still digging, but this appears to be an ordering issue: duplicate detection appears to want the abstract class/interface declaration to appear before the Invoker
definition, e.g.:
% monodis --typedef obj/Debug/net9.0-android/android/assets/arm64-v8a/Mono.Android.dll
…
7676: Java.Util.Functions.IIntSupplier (flist=57464, mlist=135763, flags=0x1000a1, extends=0x0)
7677: Java.Util.Functions.IIntSupplierInvoker (flist=57464, mlist=135764, flags=0x100000, extends=0x7d58)
This isn't the case with IExoPlayer
:
% monodis --typedef obj/Debug/net9.0-android/android/assets/arm64-v8a/Xamarin.AndroidX.Media3.ExoPlayer.dll | grep IExoPlayer
139: AndroidX.Media3.ExoPlayer.IExoPlayerInvoker (flist=20, mlist=567, flags=0x100000, extends=0x85)
…
166: AndroidX.Media3.ExoPlayer.IExoPlayer (flist=598, mlist=1671, flags=0x1000a1, extends=0x0)
Note that the type definition for IExoPlayerInvoker
comes before the definition for IExoPlayer
.
This presumably happens because there is an in-tree (non-generated) partial class
definition of IExoPlayerInvoker
: https://github.com/dotnet/android-libraries/blob/3c21f4643c5dfe74e64fec54e3679baf4dc8d067/source/androidx.media3/media3-exoplayer/Additions/AndroidX.Media3.ExoPlayer.IExoPlayer.cs#L10
(Aside: why is all this generated code checked in?)
The cause of the bug is somewhere within TypeMapGenerator
: with tons of extra logging, compare "normal" IIntSupplier
(Invoker
follows interface):
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: entry={JavaName=java/util/function/IntSupplier, ManagedName=Java.Util.Functions.IIntSupplier, Mono.Android, SkipInJavaToManaged=True}
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: entry={JavaName=java/util/function/IntSupplier, ManagedName=Java.Util.Functions.IIntSupplierInvoker, Mono.Android, SkipInJavaToManaged=False}
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: java/util/function/IntSupplier:
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: TypeMapDebugEntry{JavaName=java/util/function/IntSupplier, ManagedName=Java.Util.Functions.IIntSupplier, Mono.Android, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=True, DuplicateForJavaToManaged=}
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: TypeMapDebugEntry{JavaName=java/util/function/IntSupplier, ManagedName=Java.Util.Functions.IIntSupplierInvoker, Mono.Android, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=False, DuplicateForJavaToManaged=TypeMapDebugEntry{JavaName=java/util/function/IntSupplier, ManagedName=Java.Util.Functions.IIntSupplier, Mono.Android, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=True, DuplicateForJavaToManaged=}}
to IExoPlayer
:
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: entry={JavaName=androidx/media3/exoplayer/ExoPlayer, ManagedName=AndroidX.Media3.ExoPlayer.IExoPlayerInvoker, Xamarin.AndroidX.Media3.ExoPlayer, SkipInJavaToManaged=False}
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: entry={JavaName=androidx/media3/exoplayer/ExoPlayer, ManagedName=AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer, SkipInJavaToManaged=True}
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: androidx/media3/exoplayer/ExoPlayer:
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: TypeMapDebugEntry{JavaName=androidx/media3/exoplayer/ExoPlayer, ManagedName=AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=False, DuplicateForJavaToManaged=}
# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: TypeMapDebugEntry{JavaName=androidx/media3/exoplayer/ExoPlayer, ManagedName=AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=True, DuplicateForJavaToManaged=TypeMapDebugEntry{JavaName=androidx/media3/exoplayer/ExoPlayer, ManagedName=AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=False, DuplicateForJavaToManaged=}}
Note in particular the last two lines, which come from javaDuplicates
after the SyncDebugDuplicates(javaDuplicates)
call: https://github.com/dotnet/android/blob/78f88633baf99211a2157efbadf072d4981de1b0/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs#L267
With IExoPlayer
, IExoPlayerInvoker
isn't mentioned at all within javaDuplicates
. Why?
The bug appears to be within HandleDuplicates()
: https://github.com/dotnet/android/blob/78f88633baf99211a2157efbadf072d4981de1b0/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs#L301-L317
@@ -309,8 +335,11 @@ namespace Xamarin.Android.Tasks
TypeMapDebugEntry oldEntry = duplicates[0];
if (td.IsAbstract || td.IsInterface || oldEntry.TypeDefinition.IsAbstract || oldEntry.TypeDefinition.IsInterface) {
if (td.IsAssignableFrom (oldEntry.TypeDefinition, cache)) {
+ log.LogDebugMessage ($"# jonp: !!! {td.FullName} IsAssignableFrom {oldEntry.TypeDefinition.FullName}");
+ log.LogDebugMessage ($"# jonp: !!! entry={oldEntry}");
oldEntry.TypeDefinition = td;
oldEntry.ManagedName = GetManagedTypeName (td);
+ log.LogDebugMessage ($"# jonp: !!! updated entry={oldEntry}");
}
}
}
prints the following log messages:
# jonp: !!! AndroidX.Media3.ExoPlayer.IExoPlayer IsAssignableFrom AndroidX.Media3.ExoPlayer.IExoPlayerInvoker
# jonp: !!! entry=TypeMapDebugEntry{JavaName=androidx/media3/exoplayer/ExoPlayer, ManagedName=AndroidX.Media3.ExoPlayer.IExoPlayerInvoker, Xamarin.AndroidX.Media3.ExoPlayer, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=False, DuplicateForJavaToManaged=}
# jonp: !!! updated entry=TypeMapDebugEntry{JavaName=androidx/media3/exoplayer/ExoPlayer, ManagedName=AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer, JavaIndex=0, ManagedIndex=0, SkipInJavaToManaged=False, DuplicateForJavaToManaged=}
IExoPlayerInvoker
is "'removed".
Within the repro, there are two other types that trigger the above message::
# jonp: !!! Kotlin.Collections.AbstractList IsAssignableFrom Kotlin.Collections.AbstractListInvoker
# jonp: !!! Kotlin.Collections.AbstractSet IsAssignableFrom Kotlin.Collections.AbstractSetInvoker
Unsurprisingly, those also have partial class
declarations within dotnet/android-libraries…
@grendello: what's the rationale for this code?
If I remove that code -- such that the else
block is just duplicates.Add(entry)
-- then the app builds and runs without a crash.
Commit a017561b1e44c51a9af79fae0baaa50fe01c4123 appears to have added the HandleDebugDuplicates()
logic. I think this is the explanation:
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 inJava.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 entryEmbeddedAssemblies::binary_search()
ends up selecting it will always return the same managed type name for all aliased Java types.
@jonpryor wrote:
If I remove that code -- such that the
else
block is justduplicates.Add(entry)
-- then the app builds and runs without a crash.
It might not crash, but it's also not right either. From obj/Debug/net9.0-android/android/typemaps.arm64-v8a.ll
:
@map_java_to_managed = internal dso_local constant [12070 x %struct.TypeMapEntry] [
…
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13528_to, ; char* from
ptr @.TypeMapEntry.13540_from; char* to
}, ; 6921
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13528_to, ; char* from
ptr @.TypeMapEntry.13540_from; char* to
}, ; 6922
…
@.TypeMapEntry.13527_from = private unnamed_addr constant [72 x i8] c"AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer\00", align 1
@.TypeMapEntry.13528_to = private unnamed_addr constant [36 x i8] c"androidx/media3/exoplayer/ExoPlayer\00", align 1
…
@.TypeMapEntry.13540_from = private unnamed_addr constant [79 x i8] c"AndroidX.Media3.ExoPlayer.IExoPlayerInvoker, Xamarin.AndroidX.Media3.ExoPlayer\00", align 1
The first entry should be 13527_from
, not 13540_from
. As-is, there is no entry for IExoPlayer
!
@grendello: my current attempted fix is:
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs
index a6dbce277..91b552af3 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs
@@ -77,6 +77,11 @@ namespace Xamarin.Android.Tasks
public TypeDefinition TypeDefinition;
public bool SkipInJavaToManaged;
public TypeMapDebugEntry DuplicateForJavaToManaged;
+
+ public override string ToString ()
+ {
+ return $"TypeMapDebugEntry{{JavaName={JavaName}, ManagedName={ManagedName}, JavaIndex={JavaIndex}, ManagedIndex={ManagedIndex}, SkipInJavaToManaged={SkipInJavaToManaged}, DuplicateForJavaToManaged={DuplicateForJavaToManaged}}}";
+ }
}
// Widths include the terminating nul character but not the padding!
@@ -170,6 +175,7 @@ namespace Xamarin.Android.Tasks
bool GenerateDebug (bool skipJniAddNativeMethodRegistrationAttributeScan, string outputDirectory, bool generateNativeAssembly)
{
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebug: generateNativeAssembly: {generateNativeAssembly}");
if (generateNativeAssembly) {
return GenerateDebugNativeAssembly (skipJniAddNativeMethodRegistrationAttributeScan, outputDirectory);
}
@@ -192,11 +198,13 @@ namespace Xamarin.Android.Tasks
var javaDuplicates = new Dictionary<string, List<TypeMapDebugEntry>> (StringComparer.Ordinal);
foreach (TypeDefinition td in state.AllJavaTypes) {
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugFiles: td={td.FullName}");
UpdateApplicationConfig (td);
string moduleName = td.Module.Assembly.Name.Name;
ModuleDebugData module;
if (!modules.TryGetValue (moduleName, out module)) {
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugFiles: adding new module: {moduleName}");
string outputFileName = $"{moduleName}{TypemapExtension}";
module = new ModuleDebugData {
EntryCount = 0,
@@ -219,6 +227,8 @@ namespace Xamarin.Android.Tasks
}
TypeMapDebugEntry entry = GetDebugEntry (td, state.TypeCache);
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugFiles: entry={{JavaName={entry.JavaName}, ManagedName={entry.ManagedName}, SkipInJavaToManaged={entry.SkipInJavaToManaged}}}");
+
HandleDebugDuplicates (javaDuplicates, entry, td, state.TypeCache);
if (entry.JavaName.Length > module.JavaNameWidth)
module.JavaNameWidth = (uint)entry.JavaName.Length + 1;
@@ -230,6 +240,13 @@ namespace Xamarin.Android.Tasks
module.ManagedToJavaMap.Add (entry);
}
SyncDebugDuplicates (javaDuplicates);
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugFiles: javaDuplicates:");
+ foreach (var e in javaDuplicates) {
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugFiles: {e.Key}:");
+ foreach (var entry in e.Value) {
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugFiles: {entry}");
+ }
+ }
foreach (ModuleDebugData module in modules.Values) {
PrepareDebugMaps (module);
@@ -251,6 +268,7 @@ namespace Xamarin.Android.Tasks
bool GenerateDebugNativeAssembly (bool skipJniAddNativeMethodRegistrationAttributeScan, string outputDirectory)
{
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugNativeAssembly");
var javaToManaged = new List<TypeMapDebugEntry> ();
var managedToJava = new List<TypeMapDebugEntry> ();
@@ -259,12 +277,20 @@ namespace Xamarin.Android.Tasks
UpdateApplicationConfig (td);
TypeMapDebugEntry entry = GetDebugEntry (td, state.TypeCache);
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: entry={{JavaName={entry.JavaName}, ManagedName={entry.ManagedName}, SkipInJavaToManaged={entry.SkipInJavaToManaged}}}");
HandleDebugDuplicates (javaDuplicates, entry, td, state.TypeCache);
javaToManaged.Add (entry);
managedToJava.Add (entry);
}
SyncDebugDuplicates (javaDuplicates);
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: javaDuplicates:");
+ foreach (var e in javaDuplicates) {
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: Java type: {e.Key}:");
+ foreach (var entry in e.Value) {
+ log.LogDebugMessage ($"# jonp: TypeMapGenerator.GenerateDebugNativeAssembly: {entry}");
+ }
+ }
var data = new ModuleDebugData {
EntryCount = (uint)javaToManaged.Count,
@@ -305,14 +331,30 @@ namespace Xamarin.Android.Tasks
if (!javaDuplicates.TryGetValue (entry.JavaName, out duplicates)) {
javaDuplicates.Add (entry.JavaName, new List<TypeMapDebugEntry> { entry });
} else {
- duplicates.Add (entry);
TypeMapDebugEntry oldEntry = duplicates[0];
+ if ((td.IsAbstract || td.IsInterface) &&
+ !oldEntry.TypeDefinition.IsAbstract &&
+ !oldEntry.TypeDefinition.IsInterface &&
+ td.IsAssignableFrom (oldEntry.TypeDefinition, cache)) {
+ // We found the `Invoker` type *before* the declared type
+ // Fix things up so the abstract type is first, and the `Invoker` is considered a duplicate.
+ duplicates.Insert (0, entry);
+ oldEntry.SkipInJavaToManaged = false;
+ } else {
+ // ¯\_(ツ)_/¯
+ duplicates.Add (entry);
+ }
+ #if false
if (td.IsAbstract || td.IsInterface || oldEntry.TypeDefinition.IsAbstract || oldEntry.TypeDefinition.IsInterface) {
if (td.IsAssignableFrom (oldEntry.TypeDefinition, cache)) {
+ log.LogDebugMessage ($"# jonp: !!! {td.FullName} IsAssignableFrom {oldEntry.TypeDefinition.FullName}");
+ log.LogDebugMessage ($"# jonp: !!! entry={oldEntry}");
oldEntry.TypeDefinition = td;
oldEntry.ManagedName = GetManagedTypeName (td);
+ log.LogDebugMessage ($"# jonp: !!! updated entry={oldEntry}");
}
}
+ #endif
}
}
The good news is that this appears to work.
The bad news is that despite working, the resulting typemaps.arm64-v8a.ll
doesn't look right at all:
@map_managed_to_java = internal dso_local constant [12070 x %struct.TypeMapEntry] [
…
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13527_from, ; char* from
ptr @.TypeMapEntry.13528_to; char* to
}, ; 7491
…
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13540_from, ; char* from
ptr @.TypeMapEntry.13528_to; char* to
}, ; 7499
…
], align 8
@map_java_to_managed = internal dso_local constant [12070 x %struct.TypeMapEntry] [
…
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13528_to, ; char* from
ptr null; char* to
}, ; 6921
%struct.TypeMapEntry {
ptr @.TypeMapEntry.13528_to, ; char* from
ptr null; char* to
}, ; 6922
…
], align 8
@.TypeMapEntry.13527_from = private unnamed_addr constant [72 x i8] c"AndroidX.Media3.ExoPlayer.IExoPlayer, Xamarin.AndroidX.Media3.ExoPlayer\00", align 1
@.TypeMapEntry.13528_to = private unnamed_addr constant [36 x i8] c"androidx/media3/exoplayer/ExoPlayer\00", align 1
…
@.TypeMapEntry.13540_from = private unnamed_addr constant [79 x i8] c"AndroidX.Media3.ExoPlayer.IExoPlayerInvoker, Xamarin.AndroidX.Media3.ExoPlayer\00", align 1
The map_managed_to_java
entries look correct.
The map_java_to_managed
entries confuse me, mapping 13528_to
(androidx/media3/exoplayer/ExoPlayer
) to null
?!
But this appears to be what .NET 9 GA does with IIntSupplier
, so maybe that's fine?
Android framework version
net9.0-android
Affected platform version
.NET 9
Description
The code throw an exception when trying to create an instance of
ExoPlayer
Steps to Reproduce
Example project: media3.zip
Given other developers seem to already be using the media3 bindings, I wonder if I am doing anything wrong...?
Did you find any workaround?
No response
Relevant log output
No response