diff --git a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj
index 92c92c0ee94..c92b0e32b1a 100644
--- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj
+++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj
@@ -16,7 +16,6 @@
-
diff --git a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
index aa0a341e0bb..124edd61d93 100644
--- a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
+++ b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml
@@ -34,6 +34,9 @@
-->
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixAbstractMethodsStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixAbstractMethodsStep.cs
index 467533a0a59..c1ced554bb1 100644
--- a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixAbstractMethodsStep.cs
+++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixAbstractMethodsStep.cs
@@ -10,68 +10,43 @@
using Mono.Linker.Steps;
using Mono.Tuner;
using Xamarin.Android.Tasks;
-
-#if ILLINK
-using Resources = Microsoft.Android.Sdk.ILLink.Properties.Resources;
-#else // !ILLINK
using Resources = Xamarin.Android.Tasks.Properties.Resources;
-#endif // !ILLINK
namespace MonoDroid.Tuner
{
- ///
- /// NOTE: this step is subclassed so it can be called directly from Xamarin.Android.Build.Tasks
- ///
- public class FixAbstractMethodsStep : BaseMarkHandler
-#if !ILLINK
- , IAssemblyModifierPipelineStep
-#endif // !ILLINK
+ public class FixAbstractMethodsStep : BaseStep, IAssemblyModifierPipelineStep
{
- public override void Initialize (LinkContext context, MarkContext markContext)
+ readonly IMetadataResolver _injectedCache;
+ readonly Func _injectedGetMonoAndroidAssembly;
+ readonly Action _injectedLogMessage;
+
+ ///
+ /// Used by LinkAssembliesNoShrink and tests. Call before use.
+ ///
+ public FixAbstractMethodsStep () { }
+
+ ///
+ /// Used by when no is available.
+ ///
+ internal FixAbstractMethodsStep (
+ IMetadataResolver cache,
+ Func getMonoAndroidAssembly,
+ Action logMessage)
{
- base.Initialize (context, markContext);
- markContext.RegisterMarkTypeAction (type => ProcessType (type));
+ _injectedCache = cache;
+ _injectedGetMonoAndroidAssembly = getMonoAndroidAssembly;
+ _injectedLogMessage = logMessage;
}
- bool CheckShouldProcessAssembly (AssemblyDefinition assembly)
- {
- if (!Annotations.HasAction (assembly))
- Annotations.SetAction (assembly, AssemblyAction.Skip);
-
- if (MonoAndroidHelper.IsFrameworkAssembly (assembly))
- return false;
-
- CheckAppDomainUsage (assembly, (string msg) =>
-#if ILLINK
- Context.LogMessage (MessageContainer.CreateCustomWarningMessage (Context, msg, 6200, new MessageOrigin (), WarnVersion.ILLink5))
-#else // !ILLINK
- Context.LogWarning ("XA2000", msg)
-#endif // !ILLINK
- );
+ IMetadataResolver TypeCache => _injectedCache ?? Context;
- return assembly.MainModule.HasTypeReference ("Java.Lang.Object");
- }
-
- void UpdateAssemblyAction (AssemblyDefinition assembly)
- {
- if (Annotations.GetAction (assembly) == AssemblyAction.Copy)
- Annotations.SetAction (assembly, AssemblyAction.Save);
- }
-
- void ProcessType (TypeDefinition type)
+ public void ProcessAssembly (AssemblyDefinition assembly, StepContext context)
{
- var assembly = type.Module.Assembly;
- if (!CheckShouldProcessAssembly (assembly))
- return;
-
- if (!MightNeedFix (type))
- return;
-
- if (!FixAbstractMethods (type))
+ // Only run this step on non-main user Android assemblies
+ if (context.IsMainAssembly || !context.IsAndroidUserAssembly)
return;
- UpdateAssemblyAction (assembly);
- MarkAbstractMethodErrorType ();
+ context.IsAssemblyModified |= FixAbstractMethods (assembly);
}
internal bool FixAbstractMethods (AssemblyDefinition assembly)
@@ -84,17 +59,6 @@ internal bool FixAbstractMethods (AssemblyDefinition assembly)
return changed;
}
-#if !ILLINK
- public void ProcessAssembly (AssemblyDefinition assembly, StepContext context)
- {
- // Only run this step on non-main user Android assemblies
- if (context.IsMainAssembly || !context.IsAndroidUserAssembly)
- return;
-
- context.IsAssemblyModified |= FixAbstractMethods (assembly);
- }
-#endif // !ILLINK
-
readonly HashSet warnedAssemblies = new (StringComparer.Ordinal);
internal void CheckAppDomainUsage (AssemblyDefinition assembly, Action warn)
@@ -114,7 +78,7 @@ internal void CheckAppDomainUsage (AssemblyDefinition assembly, Action w
bool MightNeedFix (TypeDefinition type)
{
- return !type.IsAbstract && type.IsSubclassOf ("Java.Lang.Object", cache);
+ return !type.IsAbstract && type.IsSubclassOf ("Java.Lang.Object", TypeCache);
}
bool CompareTypes (TypeReference iType, TypeReference tType)
@@ -140,11 +104,11 @@ bool CompareTypes (TypeReference iType, TypeReference tType)
if (iType.Namespace != tType.Namespace)
return false;
- TypeDefinition iTypeDef = cache.Resolve (iType);
+ TypeDefinition iTypeDef = TypeCache.Resolve (iType);
if (iTypeDef == null)
return false;
- TypeDefinition tTypeDef = cache.Resolve (tType);
+ TypeDefinition tTypeDef = TypeCache.Resolve (tType);
if (tTypeDef == null)
return false;
@@ -174,7 +138,7 @@ bool IsInOverrides (MethodDefinition iMethod, MethodDefinition tMethod)
return false;
foreach (var o in tMethod.Overrides)
- if (o != null && iMethod.Name == o.Name && iMethod == cache.Resolve (o))
+ if (o != null && iMethod.Name == o.Name && iMethod == TypeCache.Resolve (o))
return true;
return false;
@@ -223,12 +187,12 @@ bool FixAbstractMethods (TypeDefinition type)
bool rv = false;
List typeMethods = new List (type.Methods);
- foreach (var baseType in type.GetBaseTypes (cache))
+ foreach (var baseType in type.GetBaseTypes (TypeCache))
typeMethods.AddRange (baseType.Methods);
foreach (var ifaceInfo in type.Interfaces) {
var iface = ifaceInfo.InterfaceType;
- var ifaceDef = cache.Resolve (iface);
+ var ifaceDef = TypeCache.Resolve (iface);
if (ifaceDef == null) {
LogMessage ($"Unable to unresolve interface: {iface.FullName}");
continue;
@@ -308,33 +272,20 @@ MethodDefinition AbstractMethodErrorConstructor {
}
}
- bool markedAbstractMethodErrorType;
-
- void MarkAbstractMethodErrorType ()
+ public override void LogMessage (string message)
{
- if (markedAbstractMethodErrorType)
+ if (_injectedLogMessage != null) {
+ _injectedLogMessage (message);
return;
- markedAbstractMethodErrorType = true;
-
-
- var td = AbstractMethodErrorConstructor.DeclaringType;
- Annotations.Mark (td);
- Annotations.SetPreserve (td, TypePreserve.Nothing);
- Annotations.AddPreservedMethod (td, AbstractMethodErrorConstructor);
- }
-
- public virtual void LogMessage (string message)
- {
- Context.LogMessage (message);
+ }
+ base.LogMessage (message);
}
AssemblyDefinition GetMonoAndroidAssembly ()
{
-#if !ILLINK
+ if (_injectedGetMonoAndroidAssembly != null)
+ return _injectedGetMonoAndroidAssembly ();
return Context.Resolver.GetAssembly ("Mono.Android.dll");
-#else // ILLINK
- return Context.GetLoadedAssembly ("Mono.Android");
-#endif // ILLINK
}
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/PostTrimmingFixAbstractMethodsStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/PostTrimmingFixAbstractMethodsStep.cs
new file mode 100644
index 00000000000..dbf3f3853e4
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/PostTrimmingFixAbstractMethodsStep.cs
@@ -0,0 +1,44 @@
+#nullable enable
+
+using System;
+using Java.Interop.Tools.Cecil;
+using Microsoft.Android.Build.Tasks;
+using Mono.Cecil;
+using Xamarin.Android.Tasks;
+
+namespace MonoDroid.Tuner;
+
+///
+/// Post-trimming version of FixAbstractMethodsStep that delegates to the core logic
+/// in . Skips framework assemblies, checks for
+/// AppDomain.CreateDomain usage, and fixes missing abstract method implementations
+/// on Java.Lang.Object subclasses.
+///
+class PostTrimmingFixAbstractMethodsStep : IAssemblyModifierPipelineStep
+{
+ readonly FixAbstractMethodsStep _step;
+ readonly Action _warn;
+
+ public PostTrimmingFixAbstractMethodsStep (
+ IMetadataResolver cache,
+ Func getMonoAndroidAssembly,
+ Action logMessage,
+ Action warn)
+ {
+ _step = new FixAbstractMethodsStep (cache, getMonoAndroidAssembly, logMessage);
+ _warn = warn;
+ }
+
+ public void ProcessAssembly (AssemblyDefinition assembly, StepContext context)
+ {
+ if (MonoAndroidHelper.IsFrameworkAssembly (assembly))
+ return;
+
+ _step.CheckAppDomainUsage (assembly, _warn);
+
+ if (!assembly.MainModule.HasTypeReference ("Java.Lang.Object"))
+ return;
+
+ context.IsAssemblyModified |= _step.FixAbstractMethods (assembly);
+ }
+}
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets
index 84e68d8bf6f..f7706bd4be0 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets
@@ -195,7 +195,6 @@
<_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" Type="MonoDroid.Tuner.PreserveApplications" />
<_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" Type="Microsoft.Android.Sdk.ILLink.PreserveRegistrations" />
<_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" Type="Microsoft.Android.Sdk.ILLink.PreserveJavaInterfaces" />
- <_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" Type="MonoDroid.Tuner.FixAbstractMethodsStep" />
<_TrimmerCustomSteps
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs
index 9dc7e99e635..cde9d9bc8f9 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs
@@ -1,7 +1,6 @@
#nullable enable
using System;
-using Mono.Linker.Steps;
using MonoDroid.Tuner;
namespace Xamarin.Android.Tasks
@@ -22,7 +21,7 @@ protected override void BuildPipeline (AssemblyPipeline pipeline, MSBuildLinkCon
{
// FixAbstractMethodsStep
var fixAbstractMethodsStep = new FixAbstractMethodsStep ();
- fixAbstractMethodsStep.Initialize (context, new EmptyMarkContext ());
+ fixAbstractMethodsStep.Initialize (context);
pipeline.Steps.Add (fixAbstractMethodsStep);
// FixLegacyResourceDesignerStep
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs
index 7a33ea3c7be..8c93973bd4e 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs
@@ -47,6 +47,22 @@ public override bool RunTask ()
var steps = new List ();
steps.Add (new StripEmbeddedLibrariesStep (Log));
+
+ // FixAbstractMethods — resolve Mono.Android once up front. If resolution fails, log
+ // the error and skip running the fix step entirely to avoid later unhandled exceptions.
+ AssemblyDefinition? monoAndroidAssembly = null;
+ try {
+ monoAndroidAssembly = resolver.Resolve (AssemblyNameReference.Parse ("Mono.Android"));
+ } catch (AssemblyResolutionException ex) {
+ Log.LogErrorFromException (ex, showStackTrace: false);
+ }
+ if (monoAndroidAssembly != null) {
+ steps.Add (new PostTrimmingFixAbstractMethodsStep (cache,
+ () => monoAndroidAssembly,
+ (msg) => Log.LogDebugMessage (msg),
+ (msg) => Log.LogCodedWarning ("XA2000", msg)));
+ }
+
if (AddKeepAlives) {
// Memoize the corlib resolution so the attempt (and any error logging) happens at most once,
// regardless of how many assemblies/methods need KeepAlive injection.
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs
index 1c995304248..ca87f1367bc 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs
@@ -8,7 +8,6 @@
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Linker;
-using Mono.Linker.Steps;
using Mono.Tuner;
using MonoDroid.Tuner;
using NUnit.Framework;
@@ -33,7 +32,7 @@ public void FixAbstractMethodsStep_SkipDimMembers ()
using (var resolver = new DirectoryAssemblyResolver (Logger, false))
using (var context = new LinkContext (resolver)) {
- step.Initialize (context, new EmptyMarkContext ());
+ step.Initialize (context);
resolver.SearchDirectories.Add (path);
var myAssemblyPath = Path.Combine (path, "MyAssembly.dll");
@@ -92,7 +91,7 @@ public void FixAbstractMethodsStep_Explicit ()
using (var resolver = new DirectoryAssemblyResolver (Logger, false))
using (var context = new LinkContext (resolver)) {
- step.Initialize (context, new EmptyMarkContext ());
+ step.Initialize (context);
resolver.SearchDirectories.Add (path);
var myAssemblyPath = Path.Combine (path, "MyAssembly.dll");
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
index c9157be3712..d6b665810ce 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
@@ -56,6 +56,7 @@
+