[NativeAOT] PreserveRegistrations does not handle [JniAddNativeMethodRegistrationAttribute] delegate types
- Dominant language
- C#
- Stars
- 2.1k
- Forks
- 579
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 252
Description
## Summary
`InvokeVirtualFromConstructorTests` (3 tests) fail on NativeAOT with `DelegateMarshalling_MissingInteropData` because `PreserveRegistrations.cs` does not handle `[JniAddNativeMethodRegistrationAttribute]`.
## Failing tests
- `InvokeVirtualFromConstructorTests.CreateJavaInstanceFirst`
- `InvokeVirtualFromConstructorTests.CreateManagedInstanceFirst_WithAllocObject`
- `InvokeVirtualFromConstructorTests.CreateManagedInstanceFirst_WithNewObject`
## Root cause
`PreserveRegistrations.cs` only processes methods with `[Register]` attributes (via `TryGetRegisterMember`). It has no awareness of `[JniAddNativeMethodRegistrationAttribute]`, which is used by `CallVirtualFromConstructorDerived.RegisterNativeMembers` to register a `CalledFromConstructorMarshalMethod` delegate as a JNI native callback.
On NativeAOT, delegate types used as unmanaged function pointers need their interop stubs generated at compile time. Because `PreserveRegistrations` never tells the AOT compiler about `CalledFromConstructorMarshalMethod`, the runtime throws `NotSupportedException: DelegateMarshalling_MissingInteropData` when `JniEnvironment.Types.RegisterNatives` tries to convert the delegate to a function pointer.
## Call path
1. `ManagedTypeManager.RegisterNativeMembers` calls `base.RegisterNativeMembers` (for empty methods string)
2. Base class `FindAndCallRegisterMethod` uses reflection to find `[JniAddNativeMethodRegistrationAttribute]` methods
3. `CallVirtualFromConstructorDerived.RegisterNativeMembers(args)` creates a `CalledFromConstructorMarshalMethod` delegate
4. Delegate passed to `JniEnvironment.Types.RegisterNatives` which needs unmanaged function pointer conversion
5. NativeAOT has no interop stub -> `DelegateMarshalling_MissingInteropData`
## Proposed fix
Extend `PreserveRegistrations` (or add a companion ILLink step) to:
1. Find methods marked with `[JniAddNativeMethodRegistrationAttribute]`
2. Analyze delegate types constructed within those methods
3. Ensure those delegate types get their interop metadata preserved for NativeAOT
This would also affect any user code that uses `[JniAddNativeMethodRegistrationAttribute]` with NativeAOT.
## Workaround
Tests are temporarily marked with `[Category("NativeAOTIgnore")]` in dotnet/java-interop.
Context: https://github.com/dotnet/android/pull/10496
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.