Skip to content

Commit 59303c4

Browse files
Replace runtime trim suppressions
Surface untraceable runtime reflection with RUC and propagate DAM through native registration and peer activation paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c9ab096 commit 59303c4

9 files changed

Lines changed: 43 additions & 76 deletions

File tree

src/Mono.Android/Android.Runtime/AndroidEnvironment.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,18 +254,14 @@ static void DetectCPUAndArchitecture (out ushort builtForCPU, out ushort running
254254
// System.Net.Http.dll!System.Net.Http.HttpClient.cctor
255255
// DO NOT REMOVE
256256
[DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (Xamarin.Android.Net.AndroidMessageHandler))]
257+
[RequiresUnreferencedCode ("The HTTP handler type can be provided by an environment variable and cannot be statically traced.")]
257258
static HttpMessageHandler GetHttpMessageHandler ()
258259
{
259-
[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Preserved by the MarkJavaObjects trimmer step.")]
260-
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
261-
static Type? TypeGetType (string typeName) =>
262-
Type.GetType (typeName, throwOnError: false);
263-
264260
if (httpMessageHandlerType is null) {
265261
var handlerTypeName = Environment.GetEnvironmentVariable ("XA_HTTP_CLIENT_HANDLER_TYPE")?.Trim ();
266262
Type? handlerType = null;
267263
if (!String.IsNullOrEmpty (handlerTypeName))
268-
handlerType = TypeGetType (handlerTypeName);
264+
handlerType = Type.GetType (handlerTypeName, throwOnError: false);
269265

270266
if (handlerType is null || !IsAcceptableHttpMessageHandlerType (handlerType)) {
271267
handlerType = GetFallbackHttpMessageHandlerType ();

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

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -461,15 +461,10 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
461461
static MethodInfo? dynamic_callback_gen;
462462

463463
// See ExportAttribute.cs
464-
[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Mono.Android.Export.dll is preserved when [Export] is used via [DynamicDependency].")]
465-
[UnconditionalSuppressMessage ("Trimming", "IL2075", Justification = "Mono.Android.Export.dll is preserved when [Export] is used via [DynamicDependency].")]
466464
static Delegate CreateDynamicCallback (MethodInfo method)
467465
{
468466
if (dynamic_callback_gen == null) {
469-
var assembly = Assembly.Load ("Mono.Android.Export");
470-
if (assembly == null)
471-
throw new InvalidOperationException ("To use methods marked with ExportAttribute, Mono.Android.Export.dll needs to be referenced in the application");
472-
var type = assembly.GetType ("Java.Interop.DynamicCallbackCodeGenerator");
467+
var type = Type.GetType ("Java.Interop.DynamicCallbackCodeGenerator, Mono.Android.Export", throwOnError: false);
473468
if (type == null)
474469
throw new InvalidOperationException ("The referenced Mono.Android.Export.dll does not match the expected version. The required type was not found.");
475470
dynamic_callback_gen = type.GetMethod ("Create");
@@ -559,17 +554,14 @@ static bool CallRegisterMethodByIndex (JniNativeMethodRegistrationArguments argu
559554
[Obsolete ("Use RegisterNativeMembers(JniType, Type, ReadOnlySpan<char>) instead.")]
560555
public override void RegisterNativeMembers (
561556
JniType nativeClass,
562-
[DynamicallyAccessedMembers (MethodsAndPrivateNested)]
557+
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.AllMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
563558
Type type,
564559
string? methods) =>
565560
RegisterNativeMembers (nativeClass, type, methods.AsSpan ());
566561

567-
[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type.GetType() can never statically know the string value parsed from parameter 'methods'.")]
568-
[UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
569-
[UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
570562
public override void RegisterNativeMembers (
571563
JniType nativeClass,
572-
[DynamicallyAccessedMembers (MethodsAndPrivateNested)] Type type,
564+
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.AllMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] Type type,
573565
ReadOnlySpan<char> methods)
574566
{
575567
try {
@@ -626,16 +618,11 @@ public override void RegisterNativeMembers (
626618
}
627619
needToRegisterNatives = true;
628620
} else {
629-
Type callbackDeclaringType = type;
630621
if (!callbackDeclaringTypeString.IsEmpty) {
631-
callbackDeclaringType = Type.GetType (callbackDeclaringTypeString.ToString (), throwOnError: true)!;
632-
}
633-
while (callbackDeclaringType.ContainsGenericParameters) {
634-
callbackDeclaringType = callbackDeclaringType.BaseType!;
622+
throw new NotSupportedException ("Callback declaring type names are not supported in trim-compatible native registration.");
635623
}
636624

637-
GetCallbackHandler connector = (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler),
638-
callbackDeclaringType, callbackString.ToString ());
625+
GetCallbackHandler connector = CreateCallbackHandler (type, callbackString.ToString ());
639626
callback = connector ();
640627
}
641628

@@ -663,6 +650,17 @@ bool ShouldRegisterDynamically (string callbackTypeName, string callbackString,
663650

664651
return String.Compare (callbackName, callbackString, StringComparison.Ordinal) == 0;
665652
}
653+
654+
}
655+
656+
static GetCallbackHandler CreateCallbackHandler (
657+
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.AllMethods)]
658+
Type callbackDeclaringType,
659+
string callbackString)
660+
{
661+
var method = callbackDeclaringType.GetMethod (callbackString, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
662+
?? throw new MissingMethodException (callbackDeclaringType.FullName, callbackString);
663+
return (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler), method);
666664
}
667665

668666
static int CountMethods (ReadOnlySpan<char> methodsSpan)
@@ -908,7 +906,7 @@ internal void RemovePeer (IJavaPeerable value, IntPtr hash)
908906
return null;
909907
}
910908

911-
public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object? []? argumentValues)
909+
public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type declaringType, ConstructorInfo cinfo, object? []? argumentValues)
912910
{
913911
Java.Interop.TypeManager.Activate (reference.Handle, cinfo, argumentValues);
914912
}

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,11 @@ static void PropagateUncaughtException (IntPtr env, IntPtr javaThread, IntPtr ja
5858
}
5959

6060
[UnmanagedCallersOnly]
61+
[RequiresUnreferencedCode ("JNI native registration receives a managed type name from native code that cannot be statically traced.")]
6162
static unsafe void RegisterJniNatives (IntPtr typeName_ptr, int typeName_len, IntPtr jniClass, IntPtr methods_ptr, int methods_len)
6263
{
63-
// FIXME: https://github.com/xamarin/xamarin-android/issues/8724
64-
[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type should be preserved by the MarkJavaObjects trimmer step.")]
65-
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
66-
static Type TypeGetType (string typeName) =>
67-
Type.GetType (typeName, throwOnError: false);
68-
6964
string typeName = new string ((char*) typeName_ptr, 0, typeName_len);
70-
var type = TypeGetType (typeName);
65+
var type = Type.GetType (typeName, throwOnError: false);
7166
if (type == null) {
7267
RuntimeNativeMethods.monodroid_log (LogLevel.Error,
7368
LogCategories.Default,

src/Mono.Android/Android.Runtime/JavaProxyThrowable.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ public static JavaProxyThrowable Create (Exception innerException)
3939
return proxy;
4040
}
4141

42-
(int lineNumber, string? methodName, string? className) GetFrameInfo (StackFrame? managedFrame, MethodBase? managedMethod)
42+
(int lineNumber, string? methodName, string? className) GetFrameInfo (StackFrame? managedFrame, DiagnosticMethodInfo? managedMethod)
4343
{
4444
string? methodName = null;
4545
string? className = null;
4646

4747
if (managedFrame == null) {
4848
if (managedMethod != null) {
4949
methodName = managedMethod.Name;
50-
className = managedMethod.DeclaringType?.FullName;
50+
className = managedMethod.DeclaringTypeName;
5151
}
5252

5353
return (-1, methodName, className);
@@ -69,7 +69,7 @@ public static JavaProxyThrowable Create (Exception innerException)
6969
methodName = managedMethod.Name;
7070
}
7171

72-
return (lineNumber, methodName, managedMethod.DeclaringType?.FullName);
72+
return (lineNumber, methodName, managedMethod.DeclaringTypeName);
7373
}
7474

7575
string frameString = managedFrame.ToString ();
@@ -120,10 +120,6 @@ void TranslateStackTrace ()
120120
// StackFrame.GetMethod() will return null under NativeAOT;
121121
// However, you can still get useful information from StackFrame.ToString():
122122
// MainActivity.OnCreate() + 0x37 at offset 55 in file:line:column <filename unknown>:0:0
123-
[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "StackFrame.GetMethod() is \"best attempt\", we handle null & exceptions")]
124-
static MethodBase? StackFrameGetMethod (StackFrame frame) =>
125-
frame.GetMethod ();
126-
127123
var trace = new StackTrace (InnerException, fNeedFileInfo: true);
128124
if (trace.FrameCount <= 0) {
129125
return;
@@ -145,7 +141,7 @@ void TranslateStackTrace ()
145141
const string Unknown = "Unknown";
146142
for (int i = 0; i < frames.Length; i++) {
147143
StackFrame managedFrame = frames[i];
148-
MethodBase? managedMethod = StackFrameGetMethod (managedFrame);
144+
DiagnosticMethodInfo? managedMethod = DiagnosticMethodInfo.Create (managedFrame);
149145

150146
// https://developer.android.com/reference/java/lang/StackTraceElement?hl=en#StackTraceElement(java.lang.String,%20java.lang.String,%20java.lang.String,%20int)
151147
(int lineNumber, string? methodName, string? declaringClass) = GetFrameInfo (managedFrame, managedMethod);

src/Mono.Android/Android.Runtime/ResourceIdManager.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace Android.Runtime
77
public static class ResourceIdManager
88
{
99
static bool id_initialized;
10+
[RequiresUnreferencedCode ("Resource designer lookup uses a type name from ResourceDesignerAttribute that cannot be statically traced.")]
1011
public static void UpdateIdValues ()
1112
{
1213
if (id_initialized)
@@ -31,13 +32,10 @@ public static void UpdateIdValues ()
3132
}
3233
}
3334

35+
[RequiresUnreferencedCode ("Resource designer lookup uses a type name from ResourceDesignerAttribute that cannot be statically traced.")]
3436
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
3537
static Type? GetResourceTypeFromAssembly (Assembly assembly)
3638
{
37-
const string rootAssembly = "Resources.UpdateIdValues() methods are trimmed away by the LinkResourceDesigner trimmer step. This codepath is not called unless $(AndroidUseDesignerAssembly) is disabled.";
38-
39-
[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = rootAssembly)]
40-
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = rootAssembly)]
4139
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
4240
static Type AssemblyGetType (Assembly a, string name) => a.GetType (name);
4341

@@ -52,4 +50,3 @@ public static void UpdateIdValues ()
5250
}
5351
}
5452
}
55-

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

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public unsafe override void CollectPeers ()
7171
while (CollectedContexts.TryDequeue (out IntPtr contextPtr)) {
7272
Debug.Assert (contextPtr != IntPtr.Zero, "CollectedContexts should not contain null pointers.");
7373
HandleContext* context = (HandleContext*)contextPtr;
74-
74+
7575
lock (RegisteredInstances) {
7676
Remove (context);
7777
}
@@ -249,10 +249,10 @@ public override void FinalizePeer (IJavaPeerable value)
249249
value.Finalized ();
250250
}
251251

252-
public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues)
252+
public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, [DynamicallyAccessedMembers (Constructors)] Type declaringType, ConstructorInfo cinfo, object?[]? argumentValues)
253253
{
254254
try {
255-
ActivateViaReflection (reference, cinfo, argumentValues);
255+
ActivateViaReflection (reference, declaringType, cinfo, argumentValues);
256256
} catch (Exception e) {
257257
var m = string.Format (
258258
CultureInfo.InvariantCulture,
@@ -267,21 +267,15 @@ public override void ActivatePeer (IJavaPeerable? self, JniObjectReference refer
267267
}
268268
}
269269

270-
void ActivateViaReflection (JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues)
270+
void ActivateViaReflection (
271+
JniObjectReference reference,
272+
[DynamicallyAccessedMembers (Constructors)] Type declaringType,
273+
ConstructorInfo cinfo,
274+
object?[]? argumentValues)
271275
{
272-
var declType = GetDeclaringType (cinfo);
273-
274-
#pragma warning disable IL2072
275-
var self = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declType);
276-
#pragma warning restore IL2072
276+
var self = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declaringType);
277277
self.SetPeerReference (reference);
278-
279278
cinfo.Invoke (self, argumentValues);
280-
281-
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "🤷‍♂️")]
282-
[return: DynamicallyAccessedMembers (Constructors)]
283-
Type GetDeclaringType (ConstructorInfo cinfo) =>
284-
cinfo.DeclaringType ?? throw new NotSupportedException ("Do not know the type to create!");
285279
}
286280

287281
public override List<JniSurfacedPeerInfo> GetSurfacedPeers ()
@@ -402,7 +396,7 @@ static void EnsureContextIsOurs (IntPtr context)
402396
if (!referenceTrackingHandles.ContainsKey (context)) {
403397
throw new InvalidOperationException ("Unknown reference tracking handle.");
404398
}
405-
}
399+
}
406400
}
407401

408402
public static HandleContext* Alloc (IJavaPeerable peer)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ static Type MakeGenericType (
6565
[UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
6666
public override void RegisterNativeMembers (
6767
JniType nativeClass,
68-
[DynamicallyAccessedMembers (MethodsAndPrivateNested)]
68+
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.AllMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
6969
Type type,
7070
ReadOnlySpan<char> methods)
7171
{

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,10 @@ public override void FinalizePeer (IJavaPeerable value)
207207
value.Finalized ();
208208
}
209209

210-
public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues)
210+
public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, [DynamicallyAccessedMembers (Constructors)] Type declaringType, ConstructorInfo cinfo, object?[]? argumentValues)
211211
{
212212
try {
213-
ActivateViaReflection (reference, cinfo, argumentValues);
213+
ActivateViaReflection (reference, declaringType, cinfo, argumentValues);
214214
} catch (Exception e) {
215215
var m = string.Format (
216216
CultureInfo.InvariantCulture,
@@ -225,21 +225,12 @@ public override void ActivatePeer (IJavaPeerable? self, JniObjectReference refer
225225
}
226226
}
227227

228-
void ActivateViaReflection (JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues)
228+
void ActivateViaReflection (JniObjectReference reference, [DynamicallyAccessedMembers (Constructors)] Type declaringType, ConstructorInfo cinfo, object?[]? argumentValues)
229229
{
230-
var declType = GetDeclaringType (cinfo);
231-
232-
#pragma warning disable IL2072
233-
var self = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declType);
234-
#pragma warning restore IL2072
230+
var self = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declaringType);
235231
self.SetPeerReference (reference);
236232

237233
cinfo.Invoke (self, argumentValues);
238-
239-
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "🤷‍♂️")]
240-
[return: DynamicallyAccessedMembers (Constructors)]
241-
Type GetDeclaringType (ConstructorInfo cinfo) =>
242-
cinfo.DeclaringType ?? throw new NotSupportedException ("Do not know the type to create!");
243234
}
244235

245236
public override List<JniSurfacedPeerInfo> GetSurfacedPeers ()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
107107

108108
public override void RegisterNativeMembers (
109109
JniType nativeClass,
110-
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
110+
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.AllMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
111111
Type type,
112112
ReadOnlySpan<char> methods)
113113
{

0 commit comments

Comments
 (0)