Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,14 @@ static void DetectCPUAndArchitecture (out ushort builtForCPU, out ushort running
// System.Net.Http.dll!System.Net.Http.HttpClient.cctor
// DO NOT REMOVE
[DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (Xamarin.Android.Net.AndroidMessageHandler))]
[RequiresUnreferencedCode ("The HTTP handler type can be provided by an environment variable and cannot be statically traced.")]
static HttpMessageHandler GetHttpMessageHandler ()
{
[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Preserved by the MarkJavaObjects trimmer step.")]
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
static Type? TypeGetType (string typeName) =>
Type.GetType (typeName, throwOnError: false);

if (httpMessageHandlerType is null) {
var handlerTypeName = Environment.GetEnvironmentVariable ("XA_HTTP_CLIENT_HANDLER_TYPE")?.Trim ();
Type? handlerType = null;
if (!String.IsNullOrEmpty (handlerTypeName))
handlerType = TypeGetType (handlerTypeName);
handlerType = Type.GetType (handlerTypeName, throwOnError: false);

if (handlerType is null || !IsAcceptableHttpMessageHandlerType (handlerType)) {
handlerType = GetFallbackHttpMessageHandlerType ();
Expand Down
36 changes: 17 additions & 19 deletions src/Mono.Android/Android.Runtime/AndroidRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -461,15 +461,10 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
static MethodInfo? dynamic_callback_gen;

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

[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type.GetType() can never statically know the string value parsed from parameter 'methods'.")]
[UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
[UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
public override void RegisterNativeMembers (
JniType nativeClass,
[DynamicallyAccessedMembers (MethodsAndPrivateNested)] Type type,
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.AllMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] Type type,
ReadOnlySpan<char> methods)
{
try {
Expand Down Expand Up @@ -626,16 +618,11 @@ public override void RegisterNativeMembers (
}
needToRegisterNatives = true;
} else {
Type callbackDeclaringType = type;
if (!callbackDeclaringTypeString.IsEmpty) {
callbackDeclaringType = Type.GetType (callbackDeclaringTypeString.ToString (), throwOnError: true)!;
}
while (callbackDeclaringType.ContainsGenericParameters) {
callbackDeclaringType = callbackDeclaringType.BaseType!;
throw new NotSupportedException ("Callback declaring type names are not supported in trim-compatible native registration.");
}

GetCallbackHandler connector = (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler),
callbackDeclaringType, callbackString.ToString ());
GetCallbackHandler connector = CreateCallbackHandler (type, callbackString.ToString ());
callback = connector ();
}

Expand Down Expand Up @@ -663,6 +650,17 @@ bool ShouldRegisterDynamically (string callbackTypeName, string callbackString,

return String.Compare (callbackName, callbackString, StringComparison.Ordinal) == 0;
}

}

static GetCallbackHandler CreateCallbackHandler (
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.AllMethods)]
Type callbackDeclaringType,
string callbackString)
{
var method = callbackDeclaringType.GetMethod (callbackString, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
?? throw new MissingMethodException (callbackDeclaringType.FullName, callbackString);
return (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler), method);
}

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

public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object? []? argumentValues)
public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type declaringType, ConstructorInfo cinfo, object? []? argumentValues)
{
Java.Interop.TypeManager.Activate (reference.Handle, cinfo, argumentValues);
}
Expand Down
83 changes: 51 additions & 32 deletions src/Mono.Android/Android.Runtime/JNIEnv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ public static partial class JNIEnv {

public static IntPtr Handle => JniEnvironment.EnvironmentPointer;

static Array ArrayCreateInstance (Type elementType, int length)
static Array ArrayCreateInstance (
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type elementType,
int length)
{
if (RuntimeFeature.TrimmableTypeMap) {
var factory = TrimmableTypeMap.Instance?.GetContainerFactory (elementType);
Expand Down Expand Up @@ -597,8 +600,10 @@ public static void CopyArray (IntPtr src, string[] dest)
dest [i] = GetString (GetObjectArrayElement (src, i), JniHandleOwnership.TransferLocalRef)!;
}

static Dictionary<Type, Func<Type?, IntPtr, int, object?>>? nativeArrayElementToManaged;
static Dictionary<Type, Func<Type?, IntPtr, int, object?>> NativeArrayElementToManaged {
delegate object? NativeArrayElementConverter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type? type, IntPtr source, int index);

static Dictionary<Type, NativeArrayElementConverter>? nativeArrayElementToManaged;
static Dictionary<Type, NativeArrayElementConverter> NativeArrayElementToManaged {
get {
if (nativeArrayElementToManaged != null)
return nativeArrayElementToManaged;
Expand All @@ -609,9 +614,9 @@ public static void CopyArray (IntPtr src, string[] dest)
}
}

static Dictionary<Type, Func<Type?, IntPtr, int, object?>> CreateNativeArrayElementToManaged ()
static Dictionary<Type, NativeArrayElementConverter> CreateNativeArrayElementToManaged ()
{
return new Dictionary<Type, Func<Type?, IntPtr, int, object?>> () {
return new Dictionary<Type, NativeArrayElementConverter> () {
{ typeof (bool), (type, source, index) => {
var r = new bool [1];
_GetBooleanArrayRegion (source, index, 1, r);
Expand Down Expand Up @@ -662,17 +667,11 @@ public static void CopyArray (IntPtr src, string[] dest)
AssertIsJavaObject (type);

IntPtr elem = GetObjectArrayElement (source, index);
return GetObject (elem, type);

// FIXME: Since a Dictionary<Type, Func> is used here, the trimmer will not be able to properly analyze `Type t`
// error IL2111: Method 'lambda expression' with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method.
[UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = "FIXME: https://github.com/xamarin/xamarin-android/issues/8724")]
static object? GetObject (IntPtr e, Type t) =>
Java.Lang.Object.GetObject (e, JniHandleOwnership.TransferLocalRef, t);
return Java.Lang.Object.GetObject (elem, JniHandleOwnership.TransferLocalRef);
} },
{ typeof (Array), (type, source, index) => {
IntPtr elem = GetObjectArrayElement (source, index);
return GetArray (elem, JniHandleOwnership.TransferLocalRef, type);
return GetArray (elem, JniHandleOwnership.TransferLocalRef);
} },
};
}
Expand Down Expand Up @@ -768,7 +767,11 @@ static unsafe void _GetDoubleArrayRegion (IntPtr array, int start, int length, d
}

#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads
public static void CopyArray (IntPtr src, Array dest, Type? elementType = null)
public static void CopyArray (
IntPtr src,
Array dest,
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type? elementType = null)
#pragma warning restore RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads
{
if (dest == null)
Expand All @@ -783,9 +786,9 @@ public static void CopyArray (IntPtr src, Array dest, Type? elementType = null)
try {
var d = (Array?) dest.GetValue (i);
if (d == null)
dest.SetValue (GetArray (a, JniHandleOwnership.DoNotTransfer, elementType.GetElementType ()), i);
dest.SetValue (GetArray (a, JniHandleOwnership.DoNotTransfer), i);
else
CopyArray (a, d, elementType.GetElementType ());
CopyArray (a, d);
} finally {
DeleteLocalRef (a);
}
Expand All @@ -805,7 +808,10 @@ static void AssertIsJavaObject (Type? targetType)
throw new NotSupportedException ("Don't know how to convert type '" + targetType.FullName + "' to an Android.Runtime.IJavaObject.");
}

public static void CopyArray<T> (IntPtr src, T[] dest)
public static void CopyArray<
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
T
> (IntPtr src, T[] dest)
{
if (dest == null)
throw new ArgumentNullException ("dest");
Expand Down Expand Up @@ -933,7 +939,11 @@ public static void CopyArray<T> (T[] src, IntPtr dest)
CopyArray (src, typeof (T), dest);
}

public static Array? GetArray (IntPtr array_ptr, JniHandleOwnership transfer, Type? element_type = null)
public static Array? GetArray (
IntPtr array_ptr,
JniHandleOwnership transfer,
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type? element_type = null)
{
try {
return _GetArray (array_ptr, element_type);
Expand All @@ -943,8 +953,10 @@ public static void CopyArray<T> (T[] src, IntPtr dest)
}
}

static Dictionary<Type, Func<Type?, IntPtr, int, Array>>? nativeArrayToManaged;
static Dictionary<Type, Func<Type?, IntPtr, int, Array>> NativeArrayToManaged {
delegate Array NativeArrayConverter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type? type, IntPtr source, int len);

static Dictionary<Type, NativeArrayConverter>? nativeArrayToManaged;
static Dictionary<Type, NativeArrayConverter> NativeArrayToManaged {
get {
if (nativeArrayToManaged != null)
return nativeArrayToManaged;
Expand All @@ -955,9 +967,9 @@ public static void CopyArray<T> (T[] src, IntPtr dest)
}
}

static Dictionary<Type, Func<Type?, IntPtr, int, Array>> CreateNativeArrayToManaged ()
static Dictionary<Type, NativeArrayConverter> CreateNativeArrayToManaged ()
{
return new Dictionary<Type, Func<Type?, IntPtr, int, Array>> () {
return new Dictionary<Type, NativeArrayConverter> () {
{ typeof (bool), (type, source, len) => {
var r = new bool [len];
CopyArray (source, r);
Expand Down Expand Up @@ -1025,19 +1037,22 @@ public static void CopyArray<T> (T[] src, IntPtr dest)
}
} },
{ typeof (IJavaObject), (type, source, len) => {
var r = ArrayCreateInstance (type!, len);
CopyArray (source, r, type);
var r = new Java.Lang.Object [len];
CopyArray (source, r);
return r;
} },
{ typeof (Array), (type, source, len) => {
var r = ArrayCreateInstance (type!, len);
CopyArray (source, r, type);
var r = new Array [len];
CopyArray (source, r);
return r;
} },
};
}

static Array? _GetArray (IntPtr array_ptr, Type? element_type)
static Array? _GetArray (
IntPtr array_ptr,
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type? element_type)
{
if (array_ptr == IntPtr.Zero)
return null;
Expand Down Expand Up @@ -1072,10 +1087,8 @@ static int _GetArrayLength (IntPtr array_ptr)

for (int i = 0; i < cnt; i++) {
Type? targetType = (element_types != null && i < element_types.Length) ? element_types [i] : null;
object? value = converter ((targetType == null || targetType.IsValueType) ? null : targetType,
array_ptr, i);
object? value = converter (null, array_ptr, i);

ret [i] = value;
ret [i] = targetType == null || targetType.IsInstanceOfType (value)
? value
: Convert.ChangeType (value, targetType, CultureInfo.InvariantCulture);
Expand All @@ -1084,7 +1097,10 @@ static int _GetArrayLength (IntPtr array_ptr)
return ret;
}

public static T[]? GetArray<T> (IntPtr array_ptr)
public static T[]? GetArray<
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
T
> (IntPtr array_ptr)
{
if (array_ptr == IntPtr.Zero)
return null;
Expand All @@ -1111,7 +1127,10 @@ public static T[]? GetArray<
return ret;
}

public static T GetArrayItem<T> (IntPtr array_ptr, int index)
public static T GetArrayItem<
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
T
> (IntPtr array_ptr, int index)
{
if (array_ptr == IntPtr.Zero)
throw new ArgumentException ("array_ptr");
Expand Down
9 changes: 2 additions & 7 deletions src/Mono.Android/Android.Runtime/JNIEnvInit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,11 @@ static void PropagateUncaughtException (IntPtr env, IntPtr javaThread, IntPtr ja
}

[UnmanagedCallersOnly]
[RequiresUnreferencedCode ("JNI native registration receives a managed type name from native code that cannot be statically traced.")]
static unsafe void RegisterJniNatives (IntPtr typeName_ptr, int typeName_len, IntPtr jniClass, IntPtr methods_ptr, int methods_len)
{
// FIXME: https://github.com/xamarin/xamarin-android/issues/8724
[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type should be preserved by the MarkJavaObjects trimmer step.")]
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
static Type TypeGetType (string typeName) =>
Type.GetType (typeName, throwOnError: false);

string typeName = new string ((char*) typeName_ptr, 0, typeName_len);
var type = TypeGetType (typeName);
var type = Type.GetType (typeName, throwOnError: false);
if (type == null) {
RuntimeNativeMethods.monodroid_log (LogLevel.Error,
LogCategories.Default,
Expand Down
14 changes: 4 additions & 10 deletions src/Mono.Android/Android.Runtime/JavaCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,6 @@ internal Java.Lang.Object[] ToArray ()
//
public void CopyTo (Array array, int array_index)
{
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "JavaCollection<T> 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)
Expand All @@ -166,11 +161,10 @@ static Type GetElementType (Array array) =>
IntPtr lrefArray = JNIEnv.CallObjectMethod (Handle, id_toArray);
for (int i = 0; i < Count; i++)
array.SetValue (
JavaConvert.FromJniHandle (
JNIEnv.GetObjectArrayElement (lrefArray, i),
JniHandleOwnership.TransferLocalRef,
GetElementType (array)),
array_index + i);
JavaConvert.FromJniHandle (
JNIEnv.GetObjectArrayElement (lrefArray, i),
JniHandleOwnership.TransferLocalRef),
array_index + i);
JNIEnv.DeleteLocalRef (lrefArray);
}

Expand Down
8 changes: 1 addition & 7 deletions src/Mono.Android/Android.Runtime/JavaList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,22 +269,16 @@ public unsafe bool Contains (object? item)

public void CopyTo (Array array, int array_index)
{
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "JavaList<T> 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)
throw new ArgumentOutOfRangeException ("array_index");
if (array.Length < array_index + Count)
throw new ArgumentException ("array");

var targetType = GetElementType (array);
int c = Count;
for (int i = 0; i < c; i++)
array.SetValue (InternalGet (i, targetType), array_index + i);
array.SetValue (InternalGet (i), array_index + i);
}

public IEnumerator GetEnumerator ()
Expand Down
Loading