Skip to content

Commit 4f10e13

Browse files
[Mono.Android] Add AndroidTypeManager.GetInvokerTypeCore() override (#9978)
Context: e347cd3 Context: #9962 Context: dotnet/java-interop@dd3c1d0 CoreCLR + `dotnet new maui -sc` (#9962) crashes: E AndroidRuntime: FATAL EXCEPTION: main E AndroidRuntime: Process: com.companyname.testmaui, PID: 25497 E AndroidRuntime: android.runtime.JavaProxyThrowable: [System.≈]: Acc_CreateAbstEx, Android.Views.LayoutInflater E AndroidRuntime: at System.Reflection.RuntimeConstructorInfo.CheckCanCreateInstance + 0x3c(Unknown Source) E AndroidRuntime: at System.Reflection.RuntimeConstructorInfo.ThrowNoInvokeException + 0x0(Unknown Source) E AndroidRuntime: at System.Reflection.RuntimeConstructorInfo.Invoke + 0xe(Unknown Source) E AndroidRuntime: at System.Reflection.ConstructorInfo.Invoke + 0x0(Unknown Source) E AndroidRuntime: at Microsoft.Android.Runtime.ManagedValueManager.TryCreatePeer + 0x3b(Unknown Source) E AndroidRuntime: at Java.Interop.JniRuntime+JniValueManager.TryCreatePeerInstance + 0x19(Unknown Source) E AndroidRuntime: at Java.Interop.JniRuntime+JniValueManager.CreatePeerInstance + 0x5a(Unknown Source) E AndroidRuntime: at Java.Interop.JniRuntime+JniValueManager.CreatePeer + 0x150(Unknown Source) E AndroidRuntime: at Java.Interop.JniRuntime+JniValueManager.GetPeer + 0x169(Unknown Source) E AndroidRuntime: at Java.Lang.Object.GetObject + 0x1d(Unknown Source) E AndroidRuntime: at Java.Lang.Object._GetObject + 0x19(Unknown Source) E AndroidRuntime: at Java.Lang.Object.GetObject + 0x1(Unknown Source) E AndroidRuntime: at Android.Views.LayoutInflater.From + 0x3f(Unknown Source) E AndroidRuntime: at Microsoft.Maui.Platform.MauiContextExtensions.GetLayoutInflater + 0x2b(Unknown Source) `AndroidTypeManager` didn't override the `JniRuntime.JniTypeManager.GetInvokerTypeCore()` method (dotnet/java-interop@dd3c1d05) and the base implementation of this method in `JniTypeManager` only looks at `JniTypeSignatureAttribute` to find the "invoker" type. .NET for Android bindings don't use `JniTypeSignatureAttribute`, they use `RegisterAttribute`; for example, consider the abstract `Android.Views.LayoutInflater` class: [Register ("android/view/LayoutInflater", DoNotGenerateAcw=true)] partial class LayoutInflater : Java.Lang.Object { } [global::Android.Runtime.Register ("android/view/LayoutInflater", DoNotGenerateAcw=true)] internal partial class LayoutInflaterInvoker : LayoutInflater { } The default `JniRuntime.JniTypeManager.GetInvokerType()` behavior will not work with .NET for Android bindings. This has historically been fine because `AndroidValueManager.CreatePeer()` / `TypeManager.CreateInstance()` would use `JavaObjectExtensions.GetInvokerType()` to obtain the `Invoker` type via "pattern-based Reflection", appending `Invoker` to the abstract type name to obtain a non-abstract constructable type. That historical behavior changed with e347cd3: CoreCLR doesn't use `AndroidValueManager`, but instead now uses `ManagedValueManager`, which *doesn't* call `TypeManager.CreateInstance()` or `JavaObjectExtensions.GetInvokerType()`. It instead relies on `JniRuntime.JniTypeManager.GetInvokerType()`, and as that was not overridden by `AndroidTypeManager`, the invoker for `LayoutInflater` could not be found, resulting in a `MemberAccessException` as we attempt to invoke the constructor on the *abstract* `LayoutInflater` type itself! [^0]. Add an `AndroidTypeManager.GetInvokerTypeCore()` method override which calls `JavaObjectExtensions.GetInvokerType` when needed to keep backwards compatibility. [^0]: The "complete" exception message would be: Cannot create an instance of Android.Views.LayoutInflater because it is an abstract class.
1 parent 8ee23d0 commit 4f10e13

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

src/Mono.Android/Android.Runtime/AndroidRuntime.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ struct JniRemappingReplacementMethod
260260

261261
bool jniAddNativeMethodRegistrationAttributePresent;
262262

263+
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
263264
const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods;
264265
const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
265266

@@ -392,6 +393,19 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
392393
};
393394
}
394395

396+
[return: DynamicallyAccessedMembers (Constructors)]
397+
protected override Type? GetInvokerTypeCore (
398+
[DynamicallyAccessedMembers (Constructors)]
399+
Type type)
400+
{
401+
if (type.IsInterface || type.IsAbstract) {
402+
return JavaObjectExtensions.GetInvokerType (type)
403+
?? base.GetInvokerTypeCore (type);
404+
}
405+
406+
return null;
407+
}
408+
395409
delegate Delegate GetCallbackHandler ();
396410

397411
static MethodInfo? dynamic_callback_gen;

0 commit comments

Comments
 (0)