Skip to content

Commit 3341169

Browse files
[TrimmableTypeMap] Java.Interop bump and update to ValueManagers and TypeManagers (#11799)
## Summary Bumps **external/Java.Interop** and aligns Mono.Android's reflection-based type and value managers with the new base-class contracts. The Java.Interop bump relaxes the `[DynamicallyAccessedMembers]` (DAM) requirements on the virtual members of `JniRuntime.ReflectionJniTypeManager` / `JniRuntime.ReflectionJniValueManager`, so the Mono.Android overrides no longer need to repeat those annotations and instead rely on targeted trimmer/AOT suppressions. This is a standalone slice of #11617 with no dependency on the trimmable type-map scanner/emitter or array codegen work. ## Changes - `external/Java.Interop` → `8d544738a` (from `70493645c`). - Drop now-redundant `[DynamicallyAccessedMembers]` annotations from the overrides in `AndroidTypeManager`, `ManagedTypeManager`, and `TrimmableTypeMapTypeManager` (`GetInvokerTypeCore`, `GetTypeForSimpleReference`, `RegisterNativeMembers`, `ActivatePeer`), replacing them with `[UnconditionalSuppressMessage]` where the trimmer still needs reassurance. - `JavaMarshalValueManager` now extends `JniRuntime.ReflectionJniValueManager` directly. It is marked `sealed` and carries `[RequiresDynamicCode]` / `[RequiresUnreferencedCode]`, uses the base `EnsureNotDisposed ()` helper, and drops its own dispose tracking and `ActivatePeer` override. - Remove the superseded `AndroidReflectionJniValueManager` and `SimpleValueManager` (and their `Mono.Android.csproj` entries). - `JNIEnvInit.CreateValueManager` creates the value manager through a local helper with the appropriate trimming/AOT suppressions for both the CoreCLR and NativeAOT paths. - No NativeAOT default change; the trimmable type/value managers are **not** part of this PR. ## Tests / baselines - Update the API-compatibility baseline: `Android.Graphics.ColorValueMarshaler.CreateGenericValue`'s `targetType` parameter no longer carries a DAM attribute (inherited from the Java.Interop base-class change). - Refresh `SimpleDotNet` CoreCLR/NativeAOT apkdesc size baselines and the NativeAOT `BuildHasNoWarnings` count, plus `BuildTest2`. ## Context Carved out of #11617. `JavaMarshalRegisteredPeers` extraction already merged via #11750. The trimmable managers, scanner/emitter, manifest, and R8 changes ship in their own PRs (#11749/#11751/#11753/#11769/#11794/#11796/#11798). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 837746b commit 3341169

17 files changed

Lines changed: 56 additions & 536 deletions

File tree

src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder)
6161
builder.TypeManager ??= CreateDefaultTypeManager ();
6262
#endif // NET
6363

64-
builder.ValueManager ??= new JavaMarshalValueManager ();
64+
builder.ValueManager ??= CreateDefaultValueManager ();
6565
builder.ObjectReferenceManager ??= new Android.Runtime.AndroidObjectReferenceManager ();
6666

6767
if (builder.InvocationPointer != IntPtr.Zero || builder.EnvironmentPointer != IntPtr.Zero)
@@ -84,6 +84,13 @@ static JniRuntime.JniTypeManager CreateDefaultTypeManager ()
8484
return new ManagedTypeManager ();
8585
}
8686

87+
[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "CoreCLR value manager is preserved by the MarkJavaObjects trimmer step.")]
88+
[UnconditionalSuppressMessage ("Trimming", "IL3050", Justification = "This value manager won't be used in Native AOT builds in the future.")]
89+
static JniRuntime.JniValueManager CreateDefaultValueManager ()
90+
{
91+
return new JavaMarshalValueManager ();
92+
}
93+
8794
public override string? GetCurrentManagedThreadName ()
8895
{
8996
return Thread.CurrentThread.Name;

src/Mono.Android/Android.App/IntentFilterAttribute.Partial.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#nullable disable
1+
#nullable enable
22

33
using System;
44

src/Mono.Android/Android.Graphics/Color.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,18 +434,13 @@ public static void RGBToHSV (int red, int green, int blue, float[] hsv)
434434

435435
public class ColorValueMarshaler : JniValueMarshaler<Color>
436436
{
437-
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
438437
const string ExpressionRequiresUnreferencedCode = "System.Linq.Expression usage may trim away required code.";
439438

440439
public override Type MarshalType {
441440
get { return typeof (int); }
442441
}
443442

444-
public override Color CreateGenericValue (
445-
ref JniObjectReference reference,
446-
JniObjectReferenceOptions options,
447-
[DynamicallyAccessedMembers (Constructors)]
448-
Type targetType)
443+
public override Color CreateGenericValue (ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType)
449444
{
450445
throw new NotImplementedException ();
451446
}

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -314,11 +314,6 @@ public override void DeleteWeakGlobalReference (ref JniObjectReference value)
314314
class AndroidTypeManager : JniRuntime.ReflectionJniTypeManager {
315315
bool jniAddNativeMethodRegistrationAttributePresent;
316316

317-
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
318-
const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods;
319-
const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
320-
const DynamicallyAccessedMemberTypes MethodsConstructors = MethodsAndPrivateNested | Constructors;
321-
322317
public AndroidTypeManager (bool jniAddNativeMethodRegistrationAttributePresent)
323318
{
324319
this.jniAddNativeMethodRegistrationAttributePresent = jniAddNativeMethodRegistrationAttributePresent;
@@ -335,7 +330,6 @@ protected override IEnumerable<Type> GetTypesForSimpleReference (string jniSimpl
335330
}
336331

337332
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "Temporary suppression until legacy typemap entries carry DAM annotations.")]
338-
[return: DynamicallyAccessedMembers (MethodsConstructors)]
339333
protected override Type? GetTypeForSimpleReference (string jniSimpleReference)
340334
{
341335
var type = base.GetTypeForSimpleReference (jniSimpleReference);
@@ -384,10 +378,7 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
384378
return JniRemappingLookup.GetReplacementMethodInfo (jniSourceType, jniMethodName, jniMethodSignature);
385379
}
386380

387-
[return: DynamicallyAccessedMembers (Constructors)]
388-
protected override Type? GetInvokerTypeCore (
389-
[DynamicallyAccessedMembers (Constructors)]
390-
Type type)
381+
protected override Type? GetInvokerTypeCore (Type type)
391382
{
392383
if (type.IsInterface || type.IsAbstract) {
393384
return JavaObjectExtensions.GetInvokerType (type)
@@ -500,17 +491,17 @@ static bool CallRegisterMethodByIndex (JniNativeMethodRegistrationArguments argu
500491
[Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan<char>) instead.")]
501492
public override void RegisterNativeMembers (
502493
JniType nativeClass,
503-
[DynamicallyAccessedMembers (MethodsAndPrivateNested)]
504494
Type type,
505495
string? methods) =>
506496
RegisterNativeMembers (nativeClass, type, methods.AsSpan ());
507497

508498
[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type.GetType() can never statically know the string value parsed from parameter 'methods'.")]
509499
[UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
500+
[UnconditionalSuppressMessage ("Trimming", "IL2070", Justification = "GetMethods can never statically know the string value parsed from parameter 'methods'.")]
510501
[UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
511502
public override void RegisterNativeMembers (
512503
JniType nativeClass,
513-
[DynamicallyAccessedMembers (MethodsAndPrivateNested)] Type type,
504+
Type type,
514505
ReadOnlySpan<char> methods)
515506
{
516507
try {
@@ -852,7 +843,7 @@ internal void RemovePeer (IJavaPeerable value, IntPtr hash)
852843

853844
public override void ActivatePeer (
854845
JniObjectReference reference,
855-
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type,
846+
Type type,
856847
ConstructorInfo cinfo,
857848
object?[]? argumentValues)
858849
{

src/Mono.Android/Android.Runtime/IJavaObjectValueMarshaler.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,13 @@
99
namespace Android.Runtime
1010
{
1111
sealed class IJavaObjectValueMarshaler : JniValueMarshaler<IJavaObject> {
12-
13-
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
1412
const string ExpressionRequiresUnreferencedCode = "System.Linq.Expression usage may trim away required code.";
1513

1614
internal static IJavaObjectValueMarshaler Instance = new IJavaObjectValueMarshaler ();
1715

1816
public override IJavaObject CreateGenericValue (
1917
ref JniObjectReference reference,
2018
JniObjectReferenceOptions options,
21-
[DynamicallyAccessedMembers (Constructors)]
2219
Type? targetType)
2320
{
2421
throw new NotImplementedException ();

src/Mono.Android/Android.Runtime/JNIEnvInit.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,21 @@ internal static JniRuntime.JniValueManager CreateValueManager ()
188188
}
189189

190190
if (RuntimeFeature.IsCoreClrRuntime) {
191-
return new JavaMarshalValueManager ();
191+
return CreateJavaMarshalValueManager ();
192192
}
193193

194194
if (RuntimeFeature.IsNativeAotRuntime) {
195-
return new JavaMarshalValueManager ();
195+
return CreateJavaMarshalValueManager ();
196196
}
197197

198198
throw new NotSupportedException ("Internal error: unknown runtime not supported");
199+
200+
[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "CoreCLR value manager is preserved by the MarkJavaObjects trimmer step.")]
201+
[UnconditionalSuppressMessage ("Trimming", "IL3050", Justification = "This value manager won't be used in Native AOT builds in the future.")]
202+
JniRuntime.JniValueManager CreateJavaMarshalValueManager ()
203+
{
204+
return new JavaMarshalValueManager ();
205+
}
199206
}
200207

201208
static void InitializeCommonState (JnienvInitializeArgs args)

src/Mono.Android/Microsoft.Android.Runtime/AndroidReflectionJniValueManager.cs

Lines changed: 0 additions & 176 deletions
This file was deleted.

src/Mono.Android/Microsoft.Android.Runtime/JavaMarshalValueManager.cs

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,20 @@
77

88
namespace Microsoft.Android.Runtime;
99

10-
class JavaMarshalValueManager : AndroidReflectionJniValueManager
10+
[RequiresDynamicCode ("This value manager is reflection-backed and can break in AOT scenarios.")]
11+
[RequiresUnreferencedCode ("This value manager is reflection-backed and relies on custom trimming rules.")]
12+
sealed class JavaMarshalValueManager : JniRuntime.ReflectionJniValueManager
1113
{
1214
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
1315
const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1416

1517
static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) };
1618

17-
bool disposed;
18-
1919
public JavaMarshalValueManager ()
2020
{
2121
JavaMarshalRegisteredPeers.InitializeIfNeeded ();
2222
}
2323

24-
protected override void Dispose (bool disposing)
25-
{
26-
disposed = true;
27-
base.Dispose (disposing);
28-
}
29-
30-
void ThrowIfDisposed ()
31-
{
32-
if (disposed)
33-
throw new ObjectDisposedException (nameof (JavaMarshalValueManager));
34-
}
35-
3624
public override void WaitForGCBridgeProcessing ()
3725
{
3826
// Intentionally empty. The Mono runtime's own implementation acknowledges this
@@ -68,7 +56,7 @@ public override void FinalizePeer (IJavaPeerable value)
6856
JavaMarshalRegisteredPeers.FinalizePeer (value);
6957
}
7058

71-
public override void ActivatePeer (JniObjectReference reference, [DynamicallyAccessedMembers (Constructors)] Type type, ConstructorInfo cinfo, object?[]? argumentValues)
59+
public override void ActivatePeer (JniObjectReference reference, Type type, ConstructorInfo cinfo, object?[]? argumentValues)
7260
{
7361
if (RuntimeFeature.TrimmableTypeMap)
7462
throw new PlatformNotSupportedException ("Activating Java peers is not supported when TrimmableTypeMap is enabled.");
@@ -87,7 +75,7 @@ public override List<JniSurfacedPeerInfo> GetSurfacedPeers ()
8775
[DynamicallyAccessedMembers (Constructors)]
8876
Type? targetType)
8977
{
90-
ThrowIfDisposed ();
78+
EnsureNotDisposed ();
9179

9280
if (!reference.IsValid) {
9381
return null;

0 commit comments

Comments
 (0)