Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[trimming] fix custom applications for TrimMode=full #8936

Merged

Conversation

jonathanpeppers
Copy link
Member

@jonathanpeppers jonathanpeppers commented May 9, 2024

Fixes: #8914
Fixes: #7301

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.

Fixes: dotnet#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.
@jonathanpeppers jonathanpeppers merged commit 98c1063 into dotnet:main May 13, 2024
47 checks passed
@jonathanpeppers jonathanpeppers deleted the TrimModeFullCustomApplication branch May 13, 2024 17:52
grendello added a commit that referenced this pull request May 14, 2024
* main:
  [trimming] fix custom applications for `TrimMode=full` (#8936)
  It's ".NET for Android", not ".NET Android" (#8933)
grendello added a commit that referenced this pull request May 14, 2024
* main:
  [trimming] fix custom applications for `TrimMode=full` (#8936)
grendello added a commit that referenced this pull request May 16, 2024
* main:
  [trimming] fix custom applications for `TrimMode=full` (#8936)
@github-actions github-actions bot locked and limited conversation to collaborators Jun 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
3 participants