Skip to content

Commit 98c1063

Browse files
[trimming] fix custom applications for TrimMode=full (#8936)
Fixes: #8914 Using a custom application with `TrimMode=full`: [Application] public class CustomApp : Application { public CustomApp(IntPtr h, JniHandleOwnership o) : base(h, o) { } } Fails with: ILLink : error IL1012: IL Trimmer has encountered an unexpected error. Please report the issue at https://aka.ms/report-illink Fatal error in IL Linker Unhandled exception. System.InvalidOperationException: Sequence contains no matching element at System.Linq.ThrowHelper.ThrowNoMatchException() at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate) at MonoDroid.Tuner.PreserveApplications.PreserveTypeProperty(CustomAttribute attribute, String property) in /Users/runner/work/1/s/xamarin-android/src/Microsoft.Android.Sdk.ILLink/PreserveApplications.cs:line 69 at MonoDroid.Tuner.PreserveApplications.PreserveApplicationAttribute(CustomAttribute attribute) in /Users/runner/work/1/s/xamarin-android/src/Microsoft.Android.Sdk.ILLink/PreserveApplications.cs:line 60 at MonoDroid.Tuner.PreserveApplications.ProcessAttributeProvider(ICustomAttributeProvider provider) in /Users/runner/work/1/s/xamarin-android/src/Microsoft.Android.Sdk.ILLink/PreserveApplications.cs:line 55 at MonoDroid.Tuner.PreserveApplications.ProcessType(TypeDefinition type) in /Users/runner/work/1/s/xamarin-android/src/Microsoft.Android.Sdk.ILLink/PreserveApplications.cs:line 43 at MonoDroid.Tuner.PreserveApplications.<Initialize>b__0_1(TypeDefinition type) in /Users/runner/work/1/s/xamarin-android/src/Microsoft.Android.Sdk.ILLink/PreserveApplications.cs:line 21 at Mono.Linker.Steps.MarkStep.MarkType(TypeReference reference, DependencyInfo reason, Nullable`1 origin) at Mono.Linker.Steps.MarkStep.MarkTypeVisibleToReflection(TypeReference type, TypeDefinition definition, DependencyInfo& reason, MessageOrigin& origin) at Mono.Linker.Steps.MarkStep.MarkEntireType(TypeDefinition type, DependencyInfo& reason) at Mono.Linker.Steps.MarkStep.MarkEntireAssembly(AssemblyDefinition assembly) at Mono.Linker.Steps.MarkStep.MarkAssembly(AssemblyDefinition assembly, DependencyInfo reason) at Mono.Linker.Steps.MarkStep.MarkModule(ModuleDefinition module, DependencyInfo reason) at Mono.Linker.Steps.MarkStep.ProcessMarkedPending() at Mono.Linker.Steps.MarkStep.Initialize() at Mono.Linker.Steps.MarkStep.Process(LinkContext context) at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step) at Mono.Linker.Pipeline.Process(LinkContext context) at Mono.Linker.Driver.Run(ILogger customLogger) at Mono.Linker.Driver.Main(String[] args) at Mono.Linker.Driver.Main(String[] args) c:\Nuget\microsoft.net.illink.tasks\9.0.0-preview.3.24172.9\build\Microsoft.NET.ILLink.targets(91,5): error NETSDK1144: Optimizing assemblies for size failed. I could update an existing `CustomApplicationClassAndMultiDex` test to reproduce the problem. What is happening is: * `TrimMode=full` makes the trimmer way more aggressive. * `Android.App.ApplicationAttribute` has various unused members trimmed away. * `BackupAgent` and `ManageSpaceActivity` properties are trimmed away. * Custom trimmer step throws an exception when trying to access these trimmed properties. The trimmer step *already* handles cases where it can't load the types and happily continues on. We should just do the same if the properties are not found: as it would mean a customer didn't set them. As a workaround, @tranb3r tried: [global::Android.App.ApplicationAttribute( ... BackupAgent = null, ManageSpaceActivity = null )] But this results in a `NullReferenceException` in `ManifestDocumentElement`: C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\34.99.0-preview.3.231\tools\Xamarin.Android.Common.targets(1460,3): error XAGJS7001: System.NullReferenceException: Object reference not set to an instance of an object. at Xamarin.Android.Manifest.ManifestDocumentElement.ResolveType(String type, ICustomAttributeProvider provider, IAssemblyResolver resolver) at Android.App.ApplicationAttribute.<>c.<.cctor>b__114_7(ApplicationAttribute self, ICustomAttributeProvider p, IAssemblyResolver r, TypeDefinitionCache cache) at Xamarin.Android.Manifest.ManifestDocumentElement`1.ToAttributeValue(String name, T value, ICustomAttributeProvider provider, IAssemblyResolver resolver, TypeDefinitionCache cache, Int32 targetSdkVersion) at Xamarin.Android.Manifest.ManifestDocumentElement`1.ToAttribute(String name, T value, String packageName, ICustomAttributeProvider provider, IAssemblyResolver resolver, TypeDefinitionCache cache, Int32 targetSdkVersion) at Xamarin.Android.Manifest.ManifestDocumentElement`1.<>c__DisplayClass8_0.<ToElement>b__1(String e) at System.Linq.Enumerable.IteratorSelectIterator`2.MoveNext() at System.Linq.Enumerable.IEnumerableWhereIterator`1.MoveNext() at System.Xml.Linq.XContainer.AddContentSkipNotify(Object content) at Xamarin.Android.Manifest.ManifestDocumentElement`1.ToElement(T value, ICollection`1 specified, String packageName, TypeDefinitionCache cache, ICustomAttributeProvider provider, IAssemblyResolver resolver, Int32 targetSdkVersion) at Android.App.ApplicationAttribute.ToElement(IAssemblyResolver resolver, String packageName, TypeDefinitionCache cache) at Xamarin.Android.Tasks.ManifestDocument.CreateApplicationElement(XElement manifest, String applicationClass, List`1 subclasses, TypeDefinitionCache cache) at Xamarin.Android.Tasks.ManifestDocument.Merge(TaskLoggingHelper log, TypeDefinitionCache cache, List`1 subclasses, String applicationClass, Boolean embed, String bundledWearApplicationName, IEnumerable`1 mergedManifestDocuments) at Xamarin.Android.Tasks.GenerateJavaStubs.MergeManifest(NativeCodeGenState codeGenState, Dictionary`2 userAssemblies) at Xamarin.Android.Tasks.GenerateJavaStubs.Run(Boolean useMarshalMethods) at Xamarin.Android.Tasks.GenerateJavaStubs.RunTask() at Microsoft.Android.Build.Tasks.AndroidTask.Execute() in /Users/runner/work/1/s/xamarin-android/external/xamarin-android-tools/src/Microsoft.Android.Build.BaseTasks/AndroidTask.cs:line 25 These does not appear to be valid settings *anyway*, but I updated the code so it would throw a more appropriate `ArgumentException` instead of `NullReferenceException` in a random location inside the method.
1 parent 2b6fcfc commit 98c1063

File tree

3 files changed

+14
-5
lines changed

3 files changed

+14
-5
lines changed

src/Microsoft.Android.Sdk.ILLink/PreserveApplications.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ void PreserveTypeProperty (CustomAttribute attribute, string property)
6666
if (!attribute.HasProperties)
6767
return;
6868

69-
var type_ref = (TypeReference) attribute.Properties.First (p => p.Name == property).Argument.Value;
69+
// NOTE: CustomAttributeNamedArgument is a struct
70+
var named_arg = attribute.Properties.FirstOrDefault (p => p.Name == property);
71+
if (named_arg.Name == null)
72+
return;
73+
74+
var type_ref = named_arg.Argument.Value as TypeReference;
7075
if (type_ref == null)
7176
return;
7277

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,9 +1083,11 @@ public void BuildAfterMultiDexIsNotRequired ()
10831083
}
10841084

10851085
[Test]
1086-
public void CustomApplicationClassAndMultiDex ()
1086+
public void CustomApplicationClassAndMultiDex ([Values (true, false)] bool isRelease)
10871087
{
10881088
var proj = CreateMultiDexRequiredApplication ();
1089+
proj.IsRelease = isRelease;
1090+
proj.TrimModeRelease = TrimMode.Full;
10891091
proj.SetProperty ("AndroidEnableMultiDex", "True");
10901092
proj.Sources.Add (new BuildItem ("Compile", "CustomApp.cs") { TextContent = () => @"
10911093
using System;
@@ -1108,7 +1110,7 @@ public override void OnCreate()
11081110
}
11091111
}
11101112
}" });
1111-
using (var b = CreateApkBuilder ("temp/CustomApplicationClassAndMultiDex")) {
1113+
using (var b = CreateApkBuilder ()) {
11121114
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
11131115
Assert.IsFalse (b.LastBuildOutput.ContainsText ("Duplicate zip entry"), "Should not get warning about [META-INF/MANIFEST.MF]");
11141116
var customAppContent = File.ReadAllText (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "src", "com", "foxsports", "test", "CustomApp.java"));

src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocumentElement.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ public static string ToString (TypeDefinition typeDef, TypeDefinitionCache cache
2929

3030
public static TypeDefinition ResolveType (string type, ICustomAttributeProvider provider, IAssemblyResolver resolver)
3131
{
32+
if (type == null)
33+
throw new ArgumentException ("Type resolution support requires a non-null Type.", nameof (type));
3234
if (provider == null)
33-
throw new ArgumentException ("Type resolution support requires an AssemblyDefinition or TypeDefinition.", "provider");
35+
throw new ArgumentException ("Type resolution support requires an AssemblyDefinition or TypeDefinition.", nameof (provider));
3436
if (resolver == null)
35-
throw new ArgumentException ("Type resolution support requires a IAssemblyResolver.", "resolver");
37+
throw new ArgumentException ("Type resolution support requires a IAssemblyResolver.", nameof (resolver));
3638

3739
// `type` is either a "bare" type "Foo.Bar", or an
3840
// assembly-qualified type "Foo.Bar, AssemblyName [Version=...]?".

0 commit comments

Comments
 (0)