|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | + |
| 4 | +namespace Microsoft.Android.Sdk.TrimmableTypeMap; |
| 5 | + |
| 6 | +/// <summary> |
| 7 | +/// Data model for a single TypeMap output assembly. |
| 8 | +/// Describes what to emit — the emitter writes this directly into a PE assembly. |
| 9 | +/// Built by <see cref="ModelBuilder"/>, consumed by <see cref="TypeMapAssemblyGenerator"/>. |
| 10 | +/// </summary> |
| 11 | +sealed class TypeMapAssemblyData |
| 12 | +{ |
| 13 | + /// <summary>Assembly name (e.g., "_MyApp.TypeMap").</summary> |
| 14 | + public required string AssemblyName { get; init; } |
| 15 | + |
| 16 | + /// <summary>Module file name (e.g., "_MyApp.TypeMap.dll").</summary> |
| 17 | + public required string ModuleName { get; init; } |
| 18 | + |
| 19 | + /// <summary>TypeMap entries — one per unique JNI name.</summary> |
| 20 | + public List<TypeMapAttributeData> Entries { get; } = new (); |
| 21 | + |
| 22 | + /// <summary>Proxy types to emit in the assembly.</summary> |
| 23 | + public List<JavaPeerProxyData> ProxyTypes { get; } = new (); |
| 24 | + |
| 25 | + /// <summary>TypeMapAssociation entries for alias groups (multiple managed types → same JNI name).</summary> |
| 26 | + public List<TypeMapAssociationData> Associations { get; } = new (); |
| 27 | + |
| 28 | + /// <summary>Assembly names that need [IgnoresAccessChecksTo] for cross-assembly n_* calls.</summary> |
| 29 | + public List<string> IgnoresAccessChecksTo { get; } = new (); |
| 30 | +} |
| 31 | + |
| 32 | +/// <summary> |
| 33 | +/// One [assembly: TypeMap("jni/name", typeof(Proxy))] or |
| 34 | +/// [assembly: TypeMap("jni/name", typeof(Proxy), typeof(Target))] entry. |
| 35 | +/// |
| 36 | +/// 2-arg (unconditional): proxy is always preserved — used for ACW types and essential runtime types. |
| 37 | +/// 3-arg (trimmable): proxy is preserved only if Target type is referenced by the app. |
| 38 | +/// </summary> |
| 39 | +sealed record TypeMapAttributeData |
| 40 | +{ |
| 41 | + /// <summary>JNI type name, e.g., "android/app/Activity".</summary> |
| 42 | + public required string JniName { get; init; } |
| 43 | + |
| 44 | + /// <summary> |
| 45 | + /// Assembly-qualified proxy type reference string. |
| 46 | + /// Either points to a generated proxy or to the original managed type. |
| 47 | + /// </summary> |
| 48 | + public required string ProxyTypeReference { get; init; } |
| 49 | + |
| 50 | + /// <summary> |
| 51 | + /// Assembly-qualified target type reference for the trimmable (3-arg) variant. |
| 52 | + /// Null for unconditional (2-arg) entries. |
| 53 | + /// The trimmer preserves the proxy only if this target type is used by the app. |
| 54 | + /// </summary> |
| 55 | + public string? TargetTypeReference { get; init; } |
| 56 | + |
| 57 | + /// <summary>True for 2-arg unconditional entries (ACW types, essential runtime types).</summary> |
| 58 | + public bool IsUnconditional => TargetTypeReference == null; |
| 59 | +} |
| 60 | + |
| 61 | +/// <summary> |
| 62 | +/// A proxy type to generate in the TypeMap assembly (subclass of JavaPeerProxy). |
| 63 | +/// </summary> |
| 64 | +sealed class JavaPeerProxyData |
| 65 | +{ |
| 66 | + /// <summary>Simple type name, e.g., "Java_Lang_Object_Proxy".</summary> |
| 67 | + public required string TypeName { get; init; } |
| 68 | + |
| 69 | + /// <summary>Namespace for all proxy types.</summary> |
| 70 | + public string Namespace { get; init; } = "_TypeMap.Proxies"; |
| 71 | + |
| 72 | + /// <summary>Reference to the managed type this proxy wraps (for ldtoken in TargetType property).</summary> |
| 73 | + public required TypeRefData TargetType { get; init; } |
| 74 | + |
| 75 | + /// <summary>Reference to the invoker type (for interfaces/abstract types). Null if not applicable.</summary> |
| 76 | + public TypeRefData? InvokerType { get; set; } |
| 77 | + |
| 78 | + /// <summary>Whether this proxy has a CreateInstance that can actually create instances.</summary> |
| 79 | + public bool HasActivation => ActivationCtor != null || InvokerType != null; |
| 80 | + |
| 81 | + /// <summary> |
| 82 | + /// Activation constructor details. Determines how CreateInstance instantiates the managed peer. |
| 83 | + /// </summary> |
| 84 | + public ActivationCtorData? ActivationCtor { get; set; } |
| 85 | + |
| 86 | + /// <summary>True if this is an open generic type definition. CreateInstance throws NotSupportedException.</summary> |
| 87 | + public bool IsGenericDefinition { get; init; } |
| 88 | + |
| 89 | + /// <summary>Whether this proxy needs ACW support (RegisterNatives + UCO wrappers + IAndroidCallableWrapper).</summary> |
| 90 | + public bool IsAcw { get; init; } |
| 91 | + |
| 92 | + /// <summary>UCO method wrappers for marshal methods (non-constructor).</summary> |
| 93 | + public List<UcoMethodData> UcoMethods { get; } = new (); |
| 94 | + |
| 95 | + /// <summary>UCO constructor wrappers.</summary> |
| 96 | + public List<UcoConstructorData> UcoConstructors { get; } = new (); |
| 97 | + |
| 98 | + /// <summary>RegisterNatives registrations (method name, JNI signature, wrapper name).</summary> |
| 99 | + public List<NativeRegistrationData> NativeRegistrations { get; } = new (); |
| 100 | +} |
| 101 | + |
| 102 | +/// <summary> |
| 103 | +/// A cross-assembly type reference (assembly name + full managed type name). |
| 104 | +/// </summary> |
| 105 | +sealed record TypeRefData |
| 106 | +{ |
| 107 | + /// <summary>Full managed type name, e.g., "Android.App.Activity" or "MyApp.Outer+Inner".</summary> |
| 108 | + public required string ManagedTypeName { get; init; } |
| 109 | + |
| 110 | + /// <summary>Assembly containing the type, e.g., "Mono.Android".</summary> |
| 111 | + public required string AssemblyName { get; init; } |
| 112 | +} |
| 113 | + |
| 114 | +/// <summary> |
| 115 | +/// An [UnmanagedCallersOnly] static wrapper for a marshal method. |
| 116 | +/// Body: load all args → call n_* callback → ret. |
| 117 | +/// </summary> |
| 118 | +sealed record UcoMethodData |
| 119 | +{ |
| 120 | + /// <summary>Name of the generated wrapper method, e.g., "n_onCreate_uco_0".</summary> |
| 121 | + public required string WrapperName { get; init; } |
| 122 | + |
| 123 | + /// <summary>Name of the n_* callback to call, e.g., "n_OnCreate".</summary> |
| 124 | + public required string CallbackMethodName { get; init; } |
| 125 | + |
| 126 | + /// <summary>Type containing the callback method.</summary> |
| 127 | + public required TypeRefData CallbackType { get; init; } |
| 128 | + |
| 129 | + /// <summary>JNI method signature, e.g., "(Landroid/os/Bundle;)V". Used to determine CLR parameter types.</summary> |
| 130 | + public required string JniSignature { get; init; } |
| 131 | +} |
| 132 | + |
| 133 | +/// <summary> |
| 134 | +/// An [UnmanagedCallersOnly] static wrapper for a constructor callback. |
| 135 | +/// Signature must match the full JNI native method signature (jnienv + self + ctor params) |
| 136 | +/// so the ABI is correct when JNI dispatches the call. |
| 137 | +/// Body: TrimmableNativeRegistration.ActivateInstance(self, typeof(TargetType)). |
| 138 | +/// </summary> |
| 139 | +sealed record UcoConstructorData |
| 140 | +{ |
| 141 | + /// <summary>Name of the generated wrapper, e.g., "nctor_0_uco".</summary> |
| 142 | + public required string WrapperName { get; init; } |
| 143 | + |
| 144 | + /// <summary>Target type to pass to ActivateInstance.</summary> |
| 145 | + public required TypeRefData TargetType { get; init; } |
| 146 | + |
| 147 | + /// <summary>JNI constructor signature, e.g., "(Landroid/content/Context;)V". Used for RegisterNatives registration.</summary> |
| 148 | + public required string JniSignature { get; init; } |
| 149 | +} |
| 150 | + |
| 151 | +/// <summary> |
| 152 | +/// One JNI native method registration in RegisterNatives. |
| 153 | +/// </summary> |
| 154 | +sealed record NativeRegistrationData |
| 155 | +{ |
| 156 | + /// <summary>JNI method name to register, e.g., "n_onCreate" or "nctor_0".</summary> |
| 157 | + public required string JniMethodName { get; init; } |
| 158 | + |
| 159 | + /// <summary>JNI method signature, e.g., "(Landroid/os/Bundle;)V".</summary> |
| 160 | + public required string JniSignature { get; init; } |
| 161 | + |
| 162 | + /// <summary>Name of the UCO wrapper method whose function pointer to register.</summary> |
| 163 | + public required string WrapperMethodName { get; init; } |
| 164 | +} |
| 165 | + |
| 166 | +/// <summary> |
| 167 | +/// Describes how the proxy's CreateInstance should construct the managed peer. |
| 168 | +/// </summary> |
| 169 | +sealed record ActivationCtorData |
| 170 | +{ |
| 171 | + /// <summary>Type that declares the activation constructor (may be a base type).</summary> |
| 172 | + public required TypeRefData DeclaringType { get; init; } |
| 173 | + |
| 174 | + /// <summary>True when the leaf type itself declares the activation ctor.</summary> |
| 175 | + public required bool IsOnLeafType { get; init; } |
| 176 | + |
| 177 | + /// <summary>The style of activation ctor (XamarinAndroid or JavaInterop).</summary> |
| 178 | + public required ActivationCtorStyle Style { get; init; } |
| 179 | +} |
| 180 | + |
| 181 | +/// <summary> |
| 182 | +/// One [assembly: TypeMapAssociation(typeof(Source), typeof(AliasProxy))] entry. |
| 183 | +/// Links a managed type to the proxy that holds its alias TypeMap entry. |
| 184 | +/// </summary> |
| 185 | +sealed record TypeMapAssociationData |
| 186 | +{ |
| 187 | + /// <summary>Assembly-qualified source type reference (the managed alias type).</summary> |
| 188 | + public required string SourceTypeReference { get; init; } |
| 189 | + |
| 190 | + /// <summary>Assembly-qualified proxy type reference (the alias holder proxy).</summary> |
| 191 | + public required string AliasProxyTypeReference { get; init; } |
| 192 | +} |
0 commit comments