Skip to content
Merged
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
40 changes: 40 additions & 0 deletions samples/NativeAOT/NativeAotTypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace NativeAOT;

partial class NativeAotTypeManager : JniRuntime.JniTypeManager {

const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods;
internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;

Expand All @@ -28,6 +29,45 @@ public NativeAotTypeManager ()
AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: NativeAotTypeManager()");
}

protected override Type? GetInvokerTypeCore (Type type)
{
const string suffix = "Invoker";

// https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L176-L186
const string assemblyGetTypeMessage = "'Invoker' types are preserved by the MarkJavaObjects trimmer step.";
const string makeGenericTypeMessage = "Generic 'Invoker' types are preserved by the MarkJavaObjects trimmer step.";

[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = assemblyGetTypeMessage)]
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = assemblyGetTypeMessage)]
[return: DynamicallyAccessedMembers (Constructors)]
static Type? AssemblyGetType (Assembly assembly, string typeName) =>
assembly.GetType (typeName);

[UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = makeGenericTypeMessage)]
[return: DynamicallyAccessedMembers (Constructors)]
static Type MakeGenericType (
[DynamicallyAccessedMembers (Constructors)]
Type type,
Type [] arguments) =>
// FIXME: https://github.com/dotnet/java-interop/issues/1192
#pragma warning disable IL3050
type.MakeGenericType (arguments);
#pragma warning restore IL3050

Type[] arguments = type.GetGenericArguments ();
if (arguments.Length == 0)
return AssemblyGetType (type.Assembly, type + suffix) ?? base.GetInvokerTypeCore (type);
Type definition = type.GetGenericTypeDefinition ();
int bt = definition.FullName!.IndexOf ("`", StringComparison.Ordinal);
if (bt == -1)
throw new NotSupportedException ("Generic type doesn't follow generic type naming convention! " + type.FullName);
Type? suffixDefinition = AssemblyGetType (definition.Assembly,
definition.FullName.Substring (0, bt) + suffix + definition.FullName.Substring (bt));
if (suffixDefinition == null)
return base.GetInvokerTypeCore (type);
return MakeGenericType (suffixDefinition, arguments);
}

public override void RegisterNativeMembers (
JniType nativeClass,
[DynamicallyAccessedMembers (MethodsAndPrivateNested)]
Expand Down
145 changes: 2 additions & 143 deletions samples/NativeAOT/NativeAotValueManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,142 +253,11 @@ public override List<JniSurfacedPeerInfo> GetSurfacedPeers ()
}
}

public override IJavaPeerable? CreatePeer (
ref JniObjectReference reference,
JniObjectReferenceOptions transfer,
[DynamicallyAccessedMembers (Constructors)]
Type? targetType)
{
if (!reference.IsValid) {
return null;
}

targetType = targetType ?? typeof (global::Java.Interop.JavaObject);
targetType = GetPeerType (targetType);

if (!typeof (IJavaPeerable).IsAssignableFrom (targetType))
throw new ArgumentException ($"targetType `{targetType.AssemblyQualifiedName}` must implement IJavaPeerable!", nameof (targetType));

var targetSig = Runtime.TypeManager.GetTypeSignature (targetType);
if (!targetSig.IsValid || targetSig.SimpleReference == null) {
throw new ArgumentException ($"Could not determine Java type corresponding to `{targetType.AssemblyQualifiedName}`.", nameof (targetType));
}

var refClass = JniEnvironment.Types.GetObjectClass (reference);
JniObjectReference targetClass;
try {
targetClass = JniEnvironment.Types.FindClass (targetSig.SimpleReference);
} catch (Exception e) {
JniObjectReference.Dispose (ref refClass);
throw new ArgumentException ($"Could not find Java class `{targetSig.SimpleReference}`.",
nameof (targetType),
e);
}

if (!JniEnvironment.Types.IsAssignableFrom (refClass, targetClass)) {
JniObjectReference.Dispose (ref refClass);
JniObjectReference.Dispose (ref targetClass);
return null;
}

JniObjectReference.Dispose (ref targetClass);

var proxy = CreatePeerProxy (ref refClass, targetType, ref reference, transfer);

if (proxy == null) {
throw new NotSupportedException (string.Format ("Could not find an appropriate constructable wrapper type for Java type '{0}', targetType='{1}'.",
JniEnvironment.Types.GetJniTypeNameFromInstance (reference), targetType));
}

proxy.SetJniManagedPeerState (proxy.JniManagedPeerState | JniManagedPeerStates.Replaceable);
return proxy;
}

[return: DynamicallyAccessedMembers (Constructors)]
static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type)
{
if (type == typeof (object))
return typeof (global::Java.Interop.JavaObject);
if (type == typeof (IJavaPeerable))
return typeof (global::Java.Interop.JavaObject);
if (type == typeof (Exception))
return typeof (global::Java.Interop.JavaException);
return type;
}

IJavaPeerable? CreatePeerProxy (
ref JniObjectReference klass,
[DynamicallyAccessedMembers (Constructors)]
Type fallbackType,
ref JniObjectReference reference,
JniObjectReferenceOptions options)
{
var jniTypeName = JniEnvironment.Types.GetJniTypeNameFromClass (klass);

Type? type = null;
while (jniTypeName != null) {
JniTypeSignature sig;
if (!JniTypeSignature.TryParse (jniTypeName, out sig))
return null;

type = Runtime.TypeManager.GetType (sig);

if (type != null) {
var peer = TryCreatePeerProxy (type, ref reference, options);
if (peer != null) {
return peer;
}
}

var super = JniEnvironment.Types.GetSuperclass (klass);
jniTypeName = super.IsValid
? JniEnvironment.Types.GetJniTypeNameFromClass (super)
: null;

JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose);
klass = super;
}
JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose);

return TryCreatePeerProxy (fallbackType, ref reference, options);
}

[return: DynamicallyAccessedMembers (Constructors)]
static Type? GetInvokerType (Type type)
{
// https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L176-L186
const string makeGenericTypeMessage = "Generic 'Invoker' types are preserved by the MarkJavaObjects trimmer step.";

[UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = makeGenericTypeMessage)]
[return: DynamicallyAccessedMembers (Constructors)]
static Type MakeGenericType (
[DynamicallyAccessedMembers (Constructors)]
Type type,
Type [] arguments) =>
// FIXME: https://github.com/dotnet/java-interop/issues/1192
#pragma warning disable IL3050
type.MakeGenericType (arguments);
#pragma warning restore IL3050

var signature = type.GetCustomAttribute<JniTypeSignatureAttribute> ();
if (signature == null || signature.InvokerType == null) {
return null;
}

Type[] arguments = type.GetGenericArguments ();
if (arguments.Length == 0)
return signature.InvokerType;

return MakeGenericType (signature.InvokerType, arguments);
}

const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;


static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) };
static readonly Type[] JIConstructorSignature = new Type [] { typeof (JniObjectReference).MakeByRefType (), typeof (JniObjectReferenceOptions) };

protected virtual IJavaPeerable? TryCreatePeerProxy (Type type, ref JniObjectReference reference, JniObjectReferenceOptions options)
protected override IJavaPeerable? TryCreatePeer (ref JniObjectReference reference, JniObjectReferenceOptions options, Type type)
{
var c = type.GetConstructor (ActivationConstructorBindingFlags, null, XAConstructorSignature, null);
if (c != null) {
Expand All @@ -400,16 +269,6 @@ static Type MakeGenericType (
JniObjectReference.Dispose (ref reference, options);
return p;
}
c = type.GetConstructor (ActivationConstructorBindingFlags, null, JIConstructorSignature, null);
if (c != null) {
var args = new object[] {
reference,
options,
};
var p = (IJavaPeerable) c.Invoke (args);
reference = (JniObjectReference) args [0];
return p;
}
return null;
return base.TryCreatePeer (ref reference, options, type);
}
}
Loading