dotnet / dotnet/android

[NativeAOT] PreserveRegistrations does not handle [JniAddNativeMethodRegistrationAttribute] delegate types

Open
#10,950 0 comments 0 reactions 0 assignees View on GitHub
Area: NativeAOT
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.