From e9ef4e6b1d40cbc473ae56503a105f2c6d2c5864 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 29 Feb 2024 12:33:10 -0600 Subject: [PATCH] [Mono.Android] is now "trimming safe" Fixes: https://github.com/xamarin/xamarin-android/issues/5652 This is a WIP. This depends on #8758, will rebase after this one is merged. --- .../trim-analyzers/trim-analyzers.props | 49 +++++++++++++++++++ src/Mono.Android/Android.OS/AsyncTask.cs | 11 ++++- .../Android.Runtime/AndroidEnvironment.cs | 41 +++++++++++----- src/Mono.Android/Android.Runtime/JNIEnv.cs | 36 +++++++++++--- .../Android.Runtime/JavaCollection.cs | 14 +++++- .../Android.Runtime/JavaDictionary.cs | 9 +++- src/Mono.Android/Android.Runtime/JavaList.cs | 18 +++++-- src/Mono.Android/Android.Runtime/JavaSet.cs | 5 +- src/Mono.Android/Android.Util/SparseArray.cs | 6 ++- .../Android.Widget/AdapterView.cs | 6 ++- .../Android.Widget/ArrayAdapter.cs | 5 +- src/Mono.Android/Java.Interop/JavaConvert.cs | 49 +++++++++++++++---- .../Java.Interop/JavaObjectExtensions.cs | 17 +++++-- src/Mono.Android/Mono.Android.csproj | 1 + src/Mono.Android/System.Linq/Extensions.cs | 12 ++++- 15 files changed, 234 insertions(+), 45 deletions(-) create mode 100644 build-tools/trim-analyzers/trim-analyzers.props diff --git a/build-tools/trim-analyzers/trim-analyzers.props b/build-tools/trim-analyzers/trim-analyzers.props new file mode 100644 index 00000000000..a76e6902b74 --- /dev/null +++ b/build-tools/trim-analyzers/trim-analyzers.props @@ -0,0 +1,49 @@ + + + + + true + true + true + + true + + + $(WarningsAsErrors); + IL2000;IL2001;IL2002;IL2003;IL2004; + IL2005;IL2006;IL2007;IL2008;IL2009; + IL2010;IL2011;IL2012;IL2013;IL2014; + IL2015;IL2016;IL2017;IL2018;IL2019; + IL2020;IL2021;IL2022;IL2023;IL2024; + IL2025;IL2026;IL2027;IL2028;IL2029; + IL2030;IL2031;IL2032;IL2033;IL2034; + IL2035;IL2036;IL2037;IL2038;IL2039; + IL2040;IL2041;IL2042;IL2043;IL2044; + IL2045;IL2046;IL2047;IL2048;IL2049; + IL2050;IL2051;IL2052;IL2053;IL2054; + IL2055;IL2056;IL2057;IL2058;IL2059; + IL2060;IL2061;IL2062;IL2063;IL2064; + IL2065;IL2066;IL2067;IL2068;IL2069; + IL2070;IL2071;IL2072;IL2073;IL2074; + IL2075;IL2076;IL2077;IL2078;IL2079; + IL2080;IL2081;IL2082;IL2083;IL2084; + IL2085;IL2086;IL2087;IL2088;IL2089; + IL2090;IL2091;IL2092;IL2093;IL2094; + IL2095;IL2096;IL2097;IL2098;IL2099; + IL2100;IL2101;IL2102;IL2103;IL2104; + IL2105;IL2106;IL2107;IL2108;IL2109; + + + + $(WarningsAsErrors); + IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056; + + + diff --git a/src/Mono.Android/Android.OS/AsyncTask.cs b/src/Mono.Android/Android.OS/AsyncTask.cs index ad5db1b113b..e66a162a145 100644 --- a/src/Mono.Android/Android.OS/AsyncTask.cs +++ b/src/Mono.Android/Android.OS/AsyncTask.cs @@ -9,7 +9,16 @@ namespace Android.OS { [global::System.Runtime.Versioning.ObsoletedOSPlatform ("android30.0")] [Register ("android/os/AsyncTask", DoNotGenerateAcw=true)] - public abstract class AsyncTask : AsyncTask { + public abstract class AsyncTask< + [DynamicallyAccessedMembers (Constructors)] + TParams, + [DynamicallyAccessedMembers (Constructors)] + TProgress, + [DynamicallyAccessedMembers (Constructors)] + TResult + > : AsyncTask { + + const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; static IntPtr java_class_handle; internal static IntPtr class_ref { diff --git a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs index edfe42ec449..2c9ab61499f 100644 --- a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs +++ b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs @@ -24,6 +24,7 @@ public static class AndroidEnvironment { static IX509TrustManager? sslTrustManager; static KeyStore? certStore; static object lock_ = new object (); + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] static Type? httpMessageHandlerType; static void SetupTrustManager () @@ -335,11 +336,25 @@ static IWebProxy GetDefaultProxy () [DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (Xamarin.Android.Net.AndroidMessageHandler))] static object GetHttpMessageHandler () { + const string justification = "DynamicDependency should preserve AndroidMessageHandler."; + + [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = justification)] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + static Type TypeGetType (string typeName) => + Type.GetType (typeName, throwOnError: false); + + [UnconditionalSuppressMessage ("Trimming", "IL2077", Justification = justification)] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + static object ActivatorCreateInstance ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type) => + Activator.CreateInstance (type); + if (httpMessageHandlerType is null) { var handlerTypeName = Environment.GetEnvironmentVariable ("XA_HTTP_CLIENT_HANDLER_TYPE")?.Trim (); Type? handlerType = null; if (!String.IsNullOrEmpty (handlerTypeName)) - handlerType = Type.GetType (handlerTypeName, throwOnError: false); + handlerType = TypeGetType (handlerTypeName); // We don't do any type checking or casting here to avoid dependency on System.Net.Http in Mono.Android.dll if (handlerType is null || !IsAcceptableHttpMessageHandlerType (handlerType)) { @@ -349,33 +364,33 @@ static object GetHttpMessageHandler () httpMessageHandlerType = handlerType; } - return Activator.CreateInstance (httpMessageHandlerType) + return ActivatorCreateInstance (httpMessageHandlerType) ?? throw new InvalidOperationException ($"Could not create an instance of HTTP message handler type {httpMessageHandlerType.AssemblyQualifiedName}"); } static bool IsAcceptableHttpMessageHandlerType (Type handlerType) { - if (Extends (handlerType, "System.Net.Http.HttpClientHandler, System.Net.Http")) { + if (Type.GetType ("System.Net.Http.HttpClientHandler, System.Net.Http", throwOnError: false) is Type httpClientHandlerType && + httpClientHandlerType.IsAssignableFrom (handlerType)) { // It's not possible to construct HttpClientHandler in this method because it would cause infinite recursion // as HttpClientHandler's constructor calls the GetHttpMessageHandler function Logger.Log (LogLevel.Warn, "MonoAndroid", $"The type {handlerType.AssemblyQualifiedName} cannot be used as the native HTTP handler because it is derived from System.Net.Htt.HttpClientHandler. Use a type that extends System.Net.Http.HttpMessageHandler instead."); return false; } - if (!Extends (handlerType, "System.Net.Http.HttpMessageHandler, System.Net.Http")) { - Logger.Log (LogLevel.Warn, "MonoAndroid", $"The type {handlerType.AssemblyQualifiedName} set as the default HTTP handler is invalid. Use a type that extends System.Net.Http.HttpMessageHandler."); - return false; + if (Type.GetType ("System.Net.Http.HttpMessageHandler, System.Net.Http", throwOnError: false) is Type httpMessageHandlerType && + httpMessageHandlerType.IsAssignableFrom (handlerType)) { + return true; } - return true; - } - - static bool Extends (Type handlerType, string baseTypeName) { - var baseType = Type.GetType (baseTypeName, throwOnError: false); - return baseType?.IsAssignableFrom (handlerType) ?? false; + // Was not an acceptable type + Logger.Log (LogLevel.Warn, "MonoAndroid", $"The type {handlerType.AssemblyQualifiedName} set as the default HTTP handler is invalid. Use a type that extends System.Net.Http.HttpMessageHandler."); + return false; } - static Type GetFallbackHttpMessageHandlerType (string typeName = "Xamarin.Android.Net.AndroidMessageHandler, Mono.Android") + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + static Type GetFallbackHttpMessageHandlerType () { + const string typeName = "Xamarin.Android.Net.AndroidMessageHandler, Mono.Android"; var handlerType = Type.GetType (typeName, throwOnError: false) ?? throw new InvalidOperationException ($"The {typeName} was not found. The type was probably linked away."); diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 80f214a1454..0f937eb6535 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -16,11 +16,27 @@ namespace Android.Runtime { public static partial class JNIEnv { + const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + [ThreadStatic] static byte[]? mvid_bytes; public static IntPtr Handle => JniEnvironment.EnvironmentPointer; + static Array ArrayCreateInstance (Type elementType, int length) => + // FIXME: https://github.com/xamarin/java.interop/issues/1192 + // IL3050 disabled in source: if someone uses NativeAOT, they will get the warning. + #pragma warning disable IL3050 + Array.CreateInstance (elementType, length); + #pragma warning restore IL3050 + + static Type MakeArrayType (Type type) => + // FIXME: https://github.com/xamarin/java.interop/issues/1192 + // IL3050 disabled in source: if someone uses NativeAOT, they will get the warning. + #pragma warning disable IL3050 + type.MakeArrayType (); + #pragma warning restore IL3050 + internal static IntPtr IdentityHash (IntPtr v) { return JNIEnvInit.LocalRefsAreIndirect ? RuntimeNativeMethods._monodroid_get_identity_hash_code (Handle, v) : v; @@ -807,7 +823,7 @@ public static void CopyArray (IntPtr src, Array dest, Type? elementType = null) throw new ArgumentNullException ("dest"); if (elementType != null && elementType.IsValueType) - AssertCompatibleArrayTypes (src, elementType.MakeArrayType ()); + AssertCompatibleArrayTypes (src, MakeArrayType (elementType)); if (elementType != null && elementType.IsArray) { for (int i = 0; i < dest.Length; ++i) { @@ -950,7 +966,7 @@ public static void CopyArray (Array source, Type elementType, IntPtr dest) throw new ArgumentNullException ("elementType"); if (elementType.IsValueType) - AssertCompatibleArrayTypes (elementType.MakeArrayType (), dest); + AssertCompatibleArrayTypes (MakeArrayType (elementType), dest); Action converter = GetConverter (CopyManagedToNativeArray, elementType, dest); @@ -1057,12 +1073,12 @@ public static void CopyArray (T[] src, IntPtr dest) } } }, { typeof (IJavaObject), (type, source, len) => { - var r = Array.CreateInstance (type!, len); + var r = ArrayCreateInstance (type!, len); CopyArray (source, r, type); return r; } }, { typeof (Array), (type, source, len) => { - var r = Array.CreateInstance (type!, len); + var r = ArrayCreateInstance (type!, len); CopyArray (source, r, type); return r; } }, @@ -1075,7 +1091,7 @@ public static void CopyArray (T[] src, IntPtr dest) return null; if (element_type != null && element_type.IsValueType) - AssertCompatibleArrayTypes (array_ptr, element_type.MakeArrayType ()); + AssertCompatibleArrayTypes (array_ptr, MakeArrayType (element_type)); int cnt = _GetArrayLength (array_ptr); @@ -1130,7 +1146,10 @@ static int _GetArrayLength (IntPtr array_ptr) return ret; } - public static T[]? GetArray (Java.Lang.Object[] array) + public static T[]? GetArray< + [DynamicallyAccessedMembers (Constructors)] + T + > (Java.Lang.Object[] array) { if (array == null) return null; @@ -1244,7 +1263,10 @@ static IntPtr GetArrayElementClass(T[] values) return FindClass (elementType); } - public static void CopyObjectArray(IntPtr source, T[] destination) + public static void CopyObjectArray< + [DynamicallyAccessedMembers (Constructors)] + T + >(IntPtr source, T[] destination) { if (source == IntPtr.Zero) return; diff --git a/src/Mono.Android/Android.Runtime/JavaCollection.cs b/src/Mono.Android/Android.Runtime/JavaCollection.cs index 70660bc24a3..8e23660f33b 100644 --- a/src/Mono.Android/Android.Runtime/JavaCollection.cs +++ b/src/Mono.Android/Android.Runtime/JavaCollection.cs @@ -14,6 +14,8 @@ namespace Android.Runtime { // java.util.Collection allows null values public class JavaCollection : Java.Lang.Object, System.Collections.ICollection { + internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + internal static IntPtr collection_class = JNIEnv.FindClass ("java/util/Collection"); internal static IntPtr id_add; @@ -148,6 +150,11 @@ internal Java.Lang.Object[] ToArray () // public void CopyTo (Array array, int array_index) { + [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "JavaCollection constructors are preserved by the MarkJavaObjects trimmer step.")] + [return: DynamicallyAccessedMembers (Constructors)] + static Type GetElementType (Array array) => + array.GetType ().GetElementType (); + if (array == null) throw new ArgumentNullException ("array"); if (array_index < 0) @@ -164,7 +171,7 @@ public void CopyTo (Array array, int array_index) JavaConvert.FromJniHandle ( JNIEnv.GetObjectArrayElement (lrefArray, i), JniHandleOwnership.TransferLocalRef, - array.GetType ().GetElementType ()), + GetElementType (array)), array_index + i); JNIEnv.DeleteLocalRef (lrefArray); } @@ -203,7 +210,10 @@ public static IntPtr ToLocalJniHandle (ICollection? items) } [Register ("java/util/Collection", DoNotGenerateAcw=true)] - public sealed class JavaCollection : JavaCollection, ICollection { + public sealed class JavaCollection< + [DynamicallyAccessedMembers (Constructors)] + T + > : JavaCollection, ICollection { public JavaCollection (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) diff --git a/src/Mono.Android/Android.Runtime/JavaDictionary.cs b/src/Mono.Android/Android.Runtime/JavaDictionary.cs index 80656dfc58c..311dbf36ebe 100644 --- a/src/Mono.Android/Android.Runtime/JavaDictionary.cs +++ b/src/Mono.Android/Android.Runtime/JavaDictionary.cs @@ -12,6 +12,8 @@ namespace Android.Runtime { // java.util.HashMap allows null keys and values public class JavaDictionary : Java.Lang.Object, System.Collections.IDictionary { + internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + class DictionaryEnumerator : IDictionaryEnumerator { IEnumerator simple_enumerator; @@ -396,7 +398,12 @@ public static IntPtr ToLocalJniHandle (IDictionary? dictionary) // it may throw. // [Register ("java/util/HashMap", DoNotGenerateAcw=true)] - public class JavaDictionary : JavaDictionary, IDictionary { + public class JavaDictionary< + [DynamicallyAccessedMembers (Constructors)] + K, + [DynamicallyAccessedMembers (Constructors)] + V + > : JavaDictionary, IDictionary { [Register (".ctor", "()V", "")] public JavaDictionary () diff --git a/src/Mono.Android/Android.Runtime/JavaList.cs b/src/Mono.Android/Android.Runtime/JavaList.cs index 980b01f386e..e1877533577 100644 --- a/src/Mono.Android/Android.Runtime/JavaList.cs +++ b/src/Mono.Android/Android.Runtime/JavaList.cs @@ -10,6 +10,7 @@ namespace Android.Runtime { // java.util.ArrayList allows null values public partial class JavaList : Java.Lang.Object, System.Collections.IList { + internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; internal static readonly JniPeerMembers list_members = new XAPeerMembers ("java/util/List", typeof (JavaList), isInterface: true); // @@ -23,7 +24,10 @@ public partial class JavaList : Java.Lang.Object, System.Collections.IList { // // https://developer.android.com/reference/java/util/List.html?hl=en#get(int) // - internal unsafe object? InternalGet (int location, Type? targetType = null) + internal unsafe object? InternalGet ( + int location, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) { const string id = "get.(I)Ljava/lang/Object;"; JniObjectReference obj; @@ -266,6 +270,11 @@ public unsafe bool Contains (object? item) public void CopyTo (Array array, int array_index) { + [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "JavaList constructors are preserved by the MarkJavaObjects trimmer step.")] + [return: DynamicallyAccessedMembers (Constructors)] + static Type GetElementType (Array array) => + array.GetType ().GetElementType (); + if (array == null) throw new ArgumentNullException ("array"); if (array_index < 0) @@ -273,7 +282,7 @@ public void CopyTo (Array array, int array_index) if (array.Length < array_index + Count) throw new ArgumentException ("array"); - var targetType = array.GetType ().GetElementType (); + var targetType = GetElementType (array); int c = Count; for (int i = 0; i < c; i++) array.SetValue (InternalGet (i, targetType), array_index + i); @@ -673,7 +682,10 @@ public virtual Java.Lang.Object [] ToArray () } [Register ("java/util/ArrayList", DoNotGenerateAcw=true)] - public class JavaList : JavaList, IList { + public class JavaList< + [DynamicallyAccessedMembers (Constructors)] + T + > : JavaList, IList { // // Exception audit: diff --git a/src/Mono.Android/Android.Runtime/JavaSet.cs b/src/Mono.Android/Android.Runtime/JavaSet.cs index c141e1058a4..b84b040289a 100644 --- a/src/Mono.Android/Android.Runtime/JavaSet.cs +++ b/src/Mono.Android/Android.Runtime/JavaSet.cs @@ -268,7 +268,10 @@ public static IntPtr ToLocalJniHandle (ICollection? items) [Register ("java/util/HashSet", DoNotGenerateAcw=true)] // java.util.HashSet allows null - public class JavaSet : JavaSet, ICollection { + public class JavaSet< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + T + > : JavaSet, ICollection { // // Exception audit: diff --git a/src/Mono.Android/Android.Util/SparseArray.cs b/src/Mono.Android/Android.Util/SparseArray.cs index 0fcd05f31f6..2a895fb7307 100644 --- a/src/Mono.Android/Android.Util/SparseArray.cs +++ b/src/Mono.Android/Android.Util/SparseArray.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using Android.Runtime; @@ -7,7 +8,10 @@ namespace Android.Util { [Register ("android/util/SparseArray", DoNotGenerateAcw=true)] - public partial class SparseArray : SparseArray + public partial class SparseArray< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + E + > : SparseArray { public SparseArray () { diff --git a/src/Mono.Android/Android.Widget/AdapterView.cs b/src/Mono.Android/Android.Widget/AdapterView.cs index 5ad2293d8e3..7689b0c39e3 100644 --- a/src/Mono.Android/Android.Widget/AdapterView.cs +++ b/src/Mono.Android/Android.Widget/AdapterView.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Android.Views; using JLO = Java.Lang.Object; @@ -49,7 +50,10 @@ public event EventHandler ItemSelectionCleared { } [Register ("android/widget/AdapterView", DoNotGenerateAcw=true)] - public abstract class AdapterView : AdapterView where T : IAdapter { + public abstract class AdapterView< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + T + > : AdapterView where T : IAdapter { public AdapterView (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) diff --git a/src/Mono.Android/Android.Widget/ArrayAdapter.cs b/src/Mono.Android/Android.Widget/ArrayAdapter.cs index cf35e67fc07..e54ce8d7c94 100644 --- a/src/Mono.Android/Android.Widget/ArrayAdapter.cs +++ b/src/Mono.Android/Android.Widget/ArrayAdapter.cs @@ -8,7 +8,10 @@ namespace Android.Widget { [Register ("android/widget/ArrayAdapter", DoNotGenerateAcw=true)] - public partial class ArrayAdapter : ArrayAdapter { + public partial class ArrayAdapter< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + T + > : ArrayAdapter { public ArrayAdapter (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) diff --git a/src/Mono.Android/Java.Interop/JavaConvert.cs b/src/Mono.Android/Java.Interop/JavaConvert.cs index c98bc8cd2f2..24d1eab985d 100644 --- a/src/Mono.Android/Java.Interop/JavaConvert.cs +++ b/src/Mono.Android/Java.Interop/JavaConvert.cs @@ -10,6 +10,7 @@ namespace Java.Interop { static class JavaConvert { + const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; static Dictionary> JniHandleConverters = new Dictionary>() { { typeof (bool), (handle, transfer) => { @@ -56,6 +57,17 @@ static class JavaConvert { static Func? GetJniHandleConverter (Type? target) { + const string justification = "JavaDictionary<,>, JavaList<>, and JavaCollection<> TODO I don't see what preserves a FromJniHandle method"; + [UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = justification)] + [UnconditionalSuppressMessage ("Trimming", "IL2068", Justification = justification)] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + static Type MakeGenericType (Type type, params Type [] typeArguments) => + // FIXME: https://github.com/xamarin/java.interop/issues/1192 + // IL3050 disabled in source: if someone uses NativeAOT, they will get the warning. + #pragma warning disable IL3050 + type.MakeGenericType (typeArguments); + #pragma warning restore IL3050 + if (target == null) return null; @@ -64,19 +76,19 @@ static class JavaConvert { if (target.IsArray) return (h, t) => JNIEnv.GetArray (h, t, target.GetElementType ()); if (target.IsGenericType && target.GetGenericTypeDefinition() == typeof (IDictionary<,>)) { - Type t = typeof (JavaDictionary<,>).MakeGenericType (target.GetGenericArguments ()); + Type t = MakeGenericType (typeof (JavaDictionary<,>), target.GetGenericArguments ()); return GetJniHandleConverterForType (t); } if (typeof (IDictionary).IsAssignableFrom (target)) return (h, t) => JavaDictionary.FromJniHandle (h, t); if (target.IsGenericType && target.GetGenericTypeDefinition() == typeof (IList<>)) { - Type t = typeof (JavaList<>).MakeGenericType (target.GetGenericArguments ()); + Type t = MakeGenericType (typeof (JavaList<>), target.GetGenericArguments ()); return GetJniHandleConverterForType (t); } if (typeof (IList).IsAssignableFrom (target)) return (h, t) => JavaList.FromJniHandle (h, t); if (target.IsGenericType && target.GetGenericTypeDefinition() == typeof (ICollection<>)) { - Type t = typeof (JavaCollection<>).MakeGenericType (target.GetGenericArguments ()); + Type t = MakeGenericType (typeof (JavaCollection<>), target.GetGenericArguments ()); return GetJniHandleConverterForType (t); } if (typeof (ICollection).IsAssignableFrom (target)) @@ -92,13 +104,19 @@ static Func GetJniHandleConverterForType ([D typeof (Func), m); } - public static T? FromJniHandle(IntPtr handle, JniHandleOwnership transfer) + public static T? FromJniHandle< + [DynamicallyAccessedMembers (Constructors)] + T + >(IntPtr handle, JniHandleOwnership transfer) { bool set; return FromJniHandle(handle, transfer, out set); } - public static T? FromJniHandle(IntPtr handle, JniHandleOwnership transfer, out bool set) + public static T? FromJniHandle< + [DynamicallyAccessedMembers (Constructors)] + T + >(IntPtr handle, JniHandleOwnership transfer, out bool set) { if (handle == IntPtr.Zero) { set = false; @@ -133,7 +151,11 @@ static Func GetJniHandleConverterForType ([D return (T?) Convert.ChangeType (v, typeof (T), CultureInfo.InvariantCulture); } - public static object? FromJniHandle (IntPtr handle, JniHandleOwnership transfer, Type? targetType = null) + public static object? FromJniHandle ( + IntPtr handle, + JniHandleOwnership transfer, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) { if (handle == IntPtr.Zero) { return null; @@ -206,13 +228,19 @@ static Func GetJniHandleConverterForType ([D return null; } - public static T? FromJavaObject(IJavaObject? value) + public static T? FromJavaObject< + [DynamicallyAccessedMembers (Constructors)] + T + >(IJavaObject? value) { bool set; return FromJavaObject(value, out set); } - public static T? FromJavaObject(IJavaObject? value, out bool set) + public static T? FromJavaObject< + [DynamicallyAccessedMembers (Constructors)] + T + >(IJavaObject? value, out bool set) { if (value == null) { set = false; @@ -245,7 +273,10 @@ static Func GetJniHandleConverterForType ([D return (T) Convert.ChangeType (value, typeof (T), CultureInfo.InvariantCulture); } - public static object? FromJavaObject (IJavaObject value, Type? targetType = null) + public static object? FromJavaObject ( + IJavaObject value, + [DynamicallyAccessedMembers (Constructors)] + Type? targetType = null) { if (value == null) return null; diff --git a/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs b/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs index 5b083487c5b..345c664c61d 100644 --- a/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs +++ b/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs @@ -17,7 +17,10 @@ public static JavaCollection ToInteroperableCollection (this ICollection instanc } [Obsolete ("Use Android.Runtime.JavaCollection.ToLocalJniHandle()")] - public static JavaCollection ToInteroperableCollection (this ICollection instance) + public static JavaCollection ToInteroperableCollection< + [DynamicallyAccessedMembers (Constructors)] + T + > (this ICollection instance) { return instance is JavaCollection ? (JavaCollection) instance : new JavaCollection (instance); } @@ -29,7 +32,10 @@ public static JavaList ToInteroperableCollection (this IList instance) } [Obsolete ("Use Android.Runtime.JavaList.ToLocalJniHandle()")] - public static JavaList ToInteroperableCollection (this IList instance) + public static JavaList ToInteroperableCollection< + [DynamicallyAccessedMembers (Constructors)] + T + > (this IList instance) { return instance is JavaList ? (JavaList) instance : new JavaList (instance); } @@ -41,7 +47,12 @@ public static JavaDictionary ToInteroperableCollection (this IDictionary instanc } [Obsolete ("Use Android.Runtime.JavaDictionary.ToLocalJniHandle()")] - public static JavaDictionary ToInteroperableCollection (this IDictionary instance) + public static JavaDictionary ToInteroperableCollection< + [DynamicallyAccessedMembers (Constructors)] + K, + [DynamicallyAccessedMembers (Constructors)] + V + > (this IDictionary instance) { return instance is JavaDictionary ? (JavaDictionary) instance : new JavaDictionary (instance); } diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index 006ebd5eb41..4ed01cacea2 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -3,6 +3,7 @@ + $(DotNetTargetFramework) diff --git a/src/Mono.Android/System.Linq/Extensions.cs b/src/Mono.Android/System.Linq/Extensions.cs index ac555e17949..c8bb0a4a740 100644 --- a/src/Mono.Android/System.Linq/Extensions.cs +++ b/src/Mono.Android/System.Linq/Extensions.cs @@ -9,6 +9,8 @@ namespace System.Linq { public static class Extensions { + const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; + static IntPtr id_next; static Extensions () @@ -40,7 +42,10 @@ internal static IEnumerator ToEnumerator_Dispose (this Java.Util.IIterator sourc } } - public static IEnumerable ToEnumerable (this Java.Lang.IIterable source) + public static IEnumerable ToEnumerable< + [DynamicallyAccessedMembers (Constructors)] + T + > (this Java.Lang.IIterable source) { if (source == null) throw new ArgumentNullException ("source"); @@ -52,7 +57,10 @@ internal static IEnumerator ToEnumerator_Dispose (this Java.Util.IIterator sourc } } - internal static IEnumerator ToEnumerator_Dispose (this Java.Util.IIterator source) + internal static IEnumerator ToEnumerator_Dispose< + [DynamicallyAccessedMembers (Constructors)] + T + > (this Java.Util.IIterator source) { using (source) while (source.HasNext) {