Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
6bae3ac
[TrimmableTypeMap] Remove post-trim generation pass
simonrozsival Jun 8, 2026
579ea8a
Bump external/Java.Interop from `b881d21` to `d7dbad5`
dependabot[bot] Jun 10, 2026
f79c0cc
Implement Android JavaMarshal value manager split
simonrozsival Jun 9, 2026
676dca4
Use pure trimmable typemap value manager
simonrozsival Jun 9, 2026
01dfd04
Use pure trimmable typemap type manager
simonrozsival Jun 9, 2026
b77c841
Propagate trimmable typemap DAM annotations
simonrozsival Jun 9, 2026
0554d57
Prefer Requires annotations for reflection managers
simonrozsival Jun 9, 2026
7d81397
Remove manager suppression attributes
simonrozsival Jun 9, 2026
1fe2ef5
Remove invoker lookup suppression attributes
simonrozsival Jun 9, 2026
7228982
Use feature guards for runtime manager selection
simonrozsival Jun 9, 2026
326f0fd
Inline CoreCLR JavaMarshal peer delegation
simonrozsival Jun 9, 2026
6a8ec68
Throw unreachable from trimmable native registration
simonrozsival Jun 9, 2026
7d3d1e3
Remove SimpleValueManager
simonrozsival Jun 10, 2026
725d433
Simplify changes to the ManagedTypeManager
simonrozsival Jun 10, 2026
caaea85
Remove the option to use ManagedTypeManager
simonrozsival Jun 10, 2026
b489d1f
Cleanup value managers
simonrozsival Jun 10, 2026
f1ce2a2
Refine trimmable typemap runtime paths
simonrozsival Jun 10, 2026
0a1072a
Reuse Java.Interop value marshalers in trimmable runtime
simonrozsival Jun 11, 2026
78cb7d6
Support JavaObjectArray in trimmable value marshaling
simonrozsival Jun 11, 2026
169bc8f
Generalize trimmable primitive value marshaling
simonrozsival Jun 11, 2026
869f183
Apply trimmable test exclusions to new runner
simonrozsival Jun 11, 2026
93ddc73
Remove LayoutInflater test contamination
simonrozsival Jun 11, 2026
933a38d
Address trimmable review cleanup
simonrozsival Jun 11, 2026
65a2cf5
Flow excluded NUnit categories from MSBuild
simonrozsival Jun 11, 2026
6b4aedb
Extract trimmable primitive marshaler helpers
simonrozsival Jun 11, 2026
80997b8
Address trimmable review feedback
simonrozsival Jun 11, 2026
6071fd0
Support trimmable custom value marshalers
simonrozsival Jun 11, 2026
d45a519
Unwrap trimmable proxy throwables
simonrozsival Jun 11, 2026
4282882
Support trimmable type manager lookups
simonrozsival Jun 11, 2026
152845b
Use trimmable CrossReferenceBridge fixture
simonrozsival Jun 11, 2026
8105789
Use trimmable method binding fixtures
simonrozsival Jun 11, 2026
7a7ca23
Support trimmable marshaler expressions
simonrozsival Jun 11, 2026
fece7d7
Remove generated value marshaler registry
simonrozsival Jun 11, 2026
b134621
Address trimmable test review feedback
simonrozsival Jun 11, 2026
6e1a69a
Fix trimmable typemap CI failures
simonrozsival Jun 12, 2026
8447f63
Simplify generated proxy trim suppression
simonrozsival Jun 12, 2026
18f39bc
Address trimmable runtime review feedback
simonrozsival Jun 12, 2026
4e40404
Clean stale trimmable typemap Java sources
simonrozsival Jun 12, 2026
7496a32
Simplify trimmable marshaler integration
simonrozsival Jun 12, 2026
f2c59bd
Re-enable trimmable GC bridge coverage
simonrozsival Jun 12, 2026
298f262
Re-enable trimmable replacement method lookup test
simonrozsival Jun 12, 2026
7ab9659
Re-enable trimmable method binding coverage
simonrozsival Jun 12, 2026
12946a7
Remove JavaProxyThrowable Exception wrapper
simonrozsival Jun 12, 2026
1cae90b
Remove ManagedPeer workarounds from trimmable PR
simonrozsival Jun 12, 2026
a53fb70
Document built-in type signature mapping choice
simonrozsival Jun 12, 2026
25a0526
Split Java marshal value manager types
simonrozsival Jun 12, 2026
a5b39d1
Simplify trimmable object array marshaling
simonrozsival Jun 12, 2026
5dff3a8
Return object references from trimmable marshaling
simonrozsival Jun 12, 2026
f928f99
Clarify trimmable local reference ownership
simonrozsival Jun 12, 2026
66c29f3
Merge origin/main into dev/simonrozsival/java-interop-1441-android
simonrozsival Jun 17, 2026
f7b0fec
Fix AndroidRuntime merge follow-ups
simonrozsival Jun 17, 2026
39583fa
Update tests + cleanup
simonrozsival Jun 17, 2026
db14c80
Remove unnecessary code
simonrozsival Jun 17, 2026
4bbc8fa
Merge remote-tracking branch 'origin/main' into android-remove-second…
Copilot Jun 17, 2026
a23c1f2
Merge latest main, resolve conflicts (keep post-trim pass removal)
Copilot Jun 17, 2026
7412129
Fix more stuff
simonrozsival Jun 17, 2026
6a0b25f
Merge remote-tracking branch 'origin/main' into dev/simonrozsival/jav…
simonrozsival Jun 17, 2026
dcdfbae
Use Java.Interop from main
simonrozsival Jun 17, 2026
89e133e
Merge PR #11604 post-trim typemap cleanup
simonrozsival Jun 18, 2026
d95a356
Remove unnecessary MakeArrayType
simonrozsival Jun 18, 2026
2ba985f
Annotate JNINativeWrapper.CreateDelegate method
simonrozsival Jun 18, 2026
8ec4aee
Drop assertions which expect AOT and trimming warnings
simonrozsival Jun 18, 2026
200b6a4
Update apkdesc files
simonrozsival Jun 18, 2026
0aa8bad
Avoid more MakeArrayType
simonrozsival Jun 18, 2026
ebc9b9e
Suppress expected runtime manager trim warnings
simonrozsival Jun 18, 2026
46bb3ff
We removed AOT warning, do not assert that there will be a warning
simonrozsival Jun 18, 2026
1392c44
Address trimmable typemap review feedback
simonrozsival Jun 18, 2026
d4dd398
[TrimmableTypeMap] Support built-in reference arrays
simonrozsival Jun 18, 2026
b76c959
[TrimmableTypeMap] Prefer dynamic array creation on CoreCLR
simonrozsival Jun 19, 2026
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
2 changes: 0 additions & 2 deletions Documentation/docs-mobile/messages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,6 @@ Either change the value in the AndroidManifest.xml to match the $(SupportedOSPla
+ [XA4250](xa4250.md): Manifest-referenced type '{type}' was not found in any scanned assembly. It may be a framework type.
+ [XA4252](xa4252.md): Insecure HTTP Maven repository URL '{url}' is not allowed. Use an HTTPS URL, or set AllowInsecureHttp="true" metadata on the item to override this check.
+ [XA4253](xa4253.md): Generated Java callable wrapper code changed: '{path}'
+ [XA4254](xa4254.md): Trimmable type map Java source input directory '{input}' and output directory '{output}' must be different.
+ [XA4255](xa4255.md): Generated trimmable type map Java source '{path}' was not found.
+ XA4300: Native library '{library}' will not be bundled because it has an unsupported ABI.
+ [XA4301](xa4301.md): Apk already contains the item `xxx`.
+ [XA4302](xa4302.md): Unhandled exception merging \`AndroidManifest.xml\`: {ex}
Expand Down
25 changes: 0 additions & 25 deletions Documentation/docs-mobile/messages/xa4254.md

This file was deleted.

27 changes: 0 additions & 27 deletions Documentation/docs-mobile/messages/xa4255.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder)
builder.TypeManager ??= CreateDefaultTypeManager ();
#endif // NET

builder.ValueManager ??= new JavaMarshalValueManager ();
builder.ValueManager ??= Android.Runtime.JNIEnvInit.CreateValueManager ();
builder.ObjectReferenceManager ??= new Android.Runtime.AndroidObjectReferenceManager ();

if (builder.InvocationPointer != IntPtr.Zero || builder.EnvironmentPointer != IntPtr.Zero)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<type fullname="Android.Runtime.RaiseThrowableEventArgs" />
<type fullname="Android.Runtime.RegisterAttribute" />
<type fullname="Android.Runtime.TypeManager" />
<type fullname="Microsoft.Android.Runtime.ManagedTypeMapping" preserve="all" />
<!--
<type fullname="Android.Runtime.XmlResourceParserReader" />
<type fullname="Android.Runtime.XmlPullParserReader" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,16 @@ void ScanAssembly (AssemblyIndex index, Dictionary<(string ManagedName, string A

var fullName = MetadataTypeNameResolver.GetFullName (typeDef, index.Reader);

// Temporarily allow [JniAddNativeMethodRegistrationAttribute] while we investigate
// which scenarios fail later in the trimmable typemap pipeline.
// if (index.MayUseJniAddNativeMethodRegistrationAttribute &&
// !IsBuiltInJniAddNativeMethodRegistrationType (fullName, index) &&
// HasJniAddNativeMethodRegistrationAttribute (typeDef, index)) {
// logger?.LogJniAddNativeMethodRegistrationAttributeError (fullName);
// }
// Framework/runtime assemblies contain internal [JniAddNativeMethodRegistration]
// users such as Java.Interop.JavaProxyObject and Java.Interop.ManagedPeer.
// The diagnostic is for user assemblies because the trimmable runtime either
// has generated replacements for framework registration or intentionally
// disables unsupported runtime paths.
if (!frameworkAssemblyNames.Contains (index.AssemblyName) &&
index.MayUseJniAddNativeMethodRegistrationAttribute &&
HasJniAddNativeMethodRegistrationAttribute (typeDef, index)) {
logger?.LogJniAddNativeMethodRegistrationAttributeError (fullName);
}

// Determine the JNI name and whether this is a known Java peer.
// Priority:
Expand Down Expand Up @@ -413,12 +416,6 @@ static bool HasJniAddNativeMethodRegistrationAttribute (TypeDefinition typeDef,
return false;
}

static bool IsBuiltInJniAddNativeMethodRegistrationType (string fullName, AssemblyIndex index)
{
return string.Equals (index.AssemblyName, "Java.Interop", StringComparison.Ordinal) &&
string.Equals (fullName, "Java.Interop.JavaProxyObject", StringComparison.Ordinal);
}

/// <summary>
/// For each virtual override method on <paramref name="typeDef"/> that wasn't already
/// collected (no direct [Register]), walks up the base type hierarchy to find a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public TrimmableTypeMapResult Execute (
ManifestConfig? manifestConfig = null,
XDocument? manifestTemplate = null,
string? packageNamingPolicy = null,
int maxArrayRank = 0,
bool generateTypeMapAssemblies = true)
int maxArrayRank = 0)
{
_ = assemblies ?? throw new ArgumentNullException (nameof (assemblies));
_ = systemRuntimeVersion ?? throw new ArgumentNullException (nameof (systemRuntimeVersion));
Expand All @@ -55,9 +54,7 @@ public TrimmableTypeMapResult Execute (
PropagateDeferredRegistrationToBaseClasses (allPeers);
PropagateCannotRegisterToDescendants (allPeers);

var generatedAssemblies = generateTypeMapAssemblies
? GenerateTypeMapAssemblies (allPeers, systemRuntimeVersion, useSharedTypemapUniverse, maxArrayRank)
: [];
var generatedAssemblies = GenerateTypeMapAssemblies (allPeers, systemRuntimeVersion, useSharedTypemapUniverse, maxArrayRank);
var jcwPeers = allPeers.Where (ShouldGenerateJcw).ToList ();
logger.LogGeneratingJcwFilesInfo (jcwPeers.Count, allPeers.Count);
var generatedJavaSources = GenerateJcwJavaSources (jcwPeers);
Expand Down
32 changes: 16 additions & 16 deletions src/Mono.Android/Android.Runtime/AndroidRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool f
if (!reference.IsValid)
return null;
var peeked = JniEnvironment.Runtime.ValueManager.PeekPeer (reference);
if (peeked is JavaProxyThrowable proxyThrowable) {
JniObjectReference.Dispose (ref reference, options);
return proxyThrowable.InnerException;
}
var peekedExc = peeked as Exception;
if (peekedExc == null) {
var throwable = Java.Lang.Object.GetObject<Java.Lang.Throwable> (reference.Handle, JniHandleOwnership.DoNotTransfer);
Expand Down Expand Up @@ -310,14 +314,14 @@ public override void DeleteWeakGlobalReference (ref JniObjectReference value)
}
}

[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Temporary suppression for Java.Interop reflection manager base.")]
[RequiresDynamicCode ("This type manager is reflection-backed and is not compatible with Native AOT.")]
[RequiresUnreferencedCode ("This type manager is reflection-backed and is not trimming-compatible.")]
class AndroidTypeManager : JniRuntime.ReflectionJniTypeManager {
bool jniAddNativeMethodRegistrationAttributePresent;

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

public AndroidTypeManager (bool jniAddNativeMethodRegistrationAttributePresent)
{
Expand All @@ -334,8 +338,7 @@ protected override IEnumerable<Type> GetTypesForSimpleReference (string jniSimpl
yield return t;
}

[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "Temporary suppression until legacy typemap entries carry DAM annotations.")]
[return: DynamicallyAccessedMembers (MethodsConstructors)]
[return: DynamicallyAccessedMembers (Methods | Constructors | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
protected override Type? GetTypeForSimpleReference (string jniSimpleReference)
{
var type = base.GetTypeForSimpleReference (jniSimpleReference);
Expand All @@ -352,7 +355,10 @@ protected override IEnumerable<Type> GetTypesForSimpleReference (string jniSimpl
if (j != null) {
return GetReplacementTypeCore (j) ?? j;
}
return base.GetSimpleReference (type);
// Intentionally don't call base.GetSimpleReference(type): Android's
// non-trimmable runtime uses the generated/registered typemap, not
// Java.Interop's JniTypeSignatureAttribute fallback.
return null;
}

protected override IEnumerable<string> GetSimpleReferences (Type type)
Expand All @@ -361,12 +367,10 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
j = GetReplacementTypeCore (j) ?? j;

if (j != null) {
yield return j;
yield break;
}
foreach (var r in base.GetSimpleReferences (type)) {
yield return r;
return [j];
}
// Keep this in sync with GetSimpleReference(): no base fallback.
return [];
}

protected override IReadOnlyList<string>? GetStaticMethodFallbackTypesCore (string jniSimpleReference)
Expand Down Expand Up @@ -402,8 +406,6 @@ 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) {
Expand Down Expand Up @@ -505,9 +507,6 @@ public override void RegisterNativeMembers (
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,
Expand Down Expand Up @@ -640,7 +639,8 @@ static void SplitMethodLine (
}
}

[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Temporary suppression for Java.Interop reflection manager base.")]
[RequiresDynamicCode ("This value manager is reflection-backed and is not compatible with Native AOT.")]
[RequiresUnreferencedCode ("This value manager is reflection-backed and is not trimming-compatible.")]
class AndroidValueManager : JniRuntime.ReflectionJniValueManager {

Dictionary<IntPtr, IdentityHashTargets> instances = new Dictionary<IntPtr, IdentityHashTargets> ();
Expand Down
41 changes: 19 additions & 22 deletions src/Mono.Android/Android.Runtime/JNIEnv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,6 @@ static int GetArrayRank (Type elementType)
return rank;
}

static Type MakeArrayType (Type type) =>
// FIXME: https://github.com/xamarin/xamarin-android/issues/8724
// 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 JniEnvironment.References.GetIdentityHashCode (new JniObjectReference (v));
Expand Down Expand Up @@ -309,10 +302,7 @@ public static IntPtr FindClass (System.Type type)
}
sig = sig.AddArrayRank (rank);

JniObjectReference local_ref = JniEnvironment.Types.FindClass (sig.Name);
IntPtr global_ref = local_ref.NewGlobalRef ().Handle;
JniObjectReference.Dispose (ref local_ref);
return global_ref;
return FindClass (sig.Name);
} catch (Java.Lang.Throwable e) {
if (!((e is Java.Lang.NoClassDefFoundError) || (e is Java.Lang.ClassNotFoundException)))
throw;
Expand Down Expand Up @@ -577,9 +567,9 @@ public static unsafe IntPtr NewString (char[]? text, int length)
return JniEnvironment.Strings.NewString (s, length).Handle;
}

static void AssertCompatibleArrayTypes (Type sourceType, IntPtr destArray)
static void AssertCompatibleArrayTypes (Type srcElementType, IntPtr destArray)
{
IntPtr grefSource = FindClass (sourceType);
IntPtr grefSource = FindArrayClassByElementType (srcElementType);
IntPtr lrefDest = GetObjectClass (destArray);
try {
if (!IsAssignableFrom (grefSource, lrefDest)) {
Expand All @@ -592,9 +582,9 @@ static void AssertCompatibleArrayTypes (Type sourceType, IntPtr destArray)
}
}

static void AssertCompatibleArrayTypes (IntPtr sourceArray, Type destType)
static void AssertCompatibleArrayTypes (IntPtr sourceArray, Type destElementType)
{
IntPtr grefDest = FindClass (destType);
IntPtr grefDest = FindArrayClassByElementType (destElementType);
IntPtr lrefSource = GetObjectClass (sourceArray);
try {
if (!IsAssignableFrom (lrefSource, grefDest)) {
Expand All @@ -607,12 +597,19 @@ static void AssertCompatibleArrayTypes (IntPtr sourceArray, Type destType)
}
}

static IntPtr FindArrayClassByElementType (Type elementType)
{
int rank = JavaNativeTypeManager.GetArrayInfo (elementType, out elementType) + 1;
var typeSignature = JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (elementType).AddArrayRank (rank);
return FindClass (typeSignature.Name);
}

public static void CopyArray (IntPtr src, bool[] dest)
{
if (dest == null)
throw new ArgumentNullException ("dest");

AssertCompatibleArrayTypes (src, typeof (bool[]));
AssertCompatibleArrayTypes (src, destElementType: typeof (bool));

_GetBooleanArrayRegion (src, 0, dest.Length, dest);
}
Expand Down Expand Up @@ -804,7 +801,7 @@ public static void CopyArray (IntPtr src, Array dest, Type? elementType = null)
throw new ArgumentNullException ("dest");

if (elementType != null && elementType.IsValueType)
AssertCompatibleArrayTypes (src, MakeArrayType (elementType));
AssertCompatibleArrayTypes (src, destElementType: elementType);

if (elementType != null && elementType.IsArray) {
for (int i = 0; i < dest.Length; ++i) {
Expand Down Expand Up @@ -840,7 +837,7 @@ public static void CopyArray<T> (IntPtr src, T[] dest)
throw new ArgumentNullException ("dest");

if (typeof (T).IsValueType)
AssertCompatibleArrayTypes (src, typeof (T[]));
AssertCompatibleArrayTypes (src, destElementType: typeof (T));

if (typeof (T).IsArray) {
CopyArray (src, dest, typeof (T));
Expand All @@ -858,7 +855,7 @@ public static unsafe void CopyArray (bool[] src, IntPtr dest)
if (src == null)
throw new ArgumentNullException ("src");

AssertCompatibleArrayTypes (typeof (bool[]), dest);
AssertCompatibleArrayTypes (srcElementType: typeof (bool), dest);

fixed (bool* p = src)
JniEnvironment.Arrays.SetBooleanArrayRegion (new JniObjectReference (dest), 0, src.Length, p);
Expand Down Expand Up @@ -947,7 +944,7 @@ public static void CopyArray (Array source, Type elementType, IntPtr dest)
throw new ArgumentNullException ("elementType");

if (elementType.IsValueType)
AssertCompatibleArrayTypes (MakeArrayType (elementType), dest);
AssertCompatibleArrayTypes (srcElementType: elementType, dest);

Action<Array, IntPtr> converter = GetConverter (CopyManagedToNativeArray, elementType, dest);

Expand Down Expand Up @@ -1072,7 +1069,7 @@ public static void CopyArray<T> (T[] src, IntPtr dest)
return null;

if (element_type != null && element_type.IsValueType)
AssertCompatibleArrayTypes (array_ptr, MakeArrayType (element_type));
AssertCompatibleArrayTypes (array_ptr, destElementType: element_type);

int cnt = _GetArrayLength (array_ptr);

Expand Down Expand Up @@ -1119,7 +1116,7 @@ static int _GetArrayLength (IntPtr array_ptr)
return null;

if (typeof (T).IsValueType)
AssertCompatibleArrayTypes (array_ptr, typeof (T[]));
AssertCompatibleArrayTypes (array_ptr, destElementType: typeof (T));

int cnt = _GetArrayLength (array_ptr);
T[] ret = new T [cnt];
Expand Down
Loading
Loading