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] Disable assembly scanning for types implementing IVisual #20417

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions docs/design/FeatureSwitches.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ Certain features of MAUI can be enabled or disabled using feature switches. The
| MSBuild Property Name | AppContext Setting | Description |
|-|-|-|
| MauiXamlRuntimeParsingSupport | Microsoft.Maui.RuntimeFeature.IsXamlRuntimeParsingSupported | When disabled, all XAML loading at runtime will throw an exception. This will affect usage of APIs such as the `LoadFromXaml` extension method. This feature can be safely turned off when all XAML resources are compiled using XamlC (see [XAML compilation](https://learn.microsoft.com/en-us/dotnet/maui/xaml/xamlc)). This feature is enabled by default for all configurations except for NativeAOT. |
| MauiEnableIVisualAssemblyScanning | Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled | When enabled, MAUI will scan assemblies for types implementing `IVisual` and for `[assembly: Visual(...)]` attributes and register these types. |

## MauiXamlRuntimeParsingSupport

When this feature is disabled, the following APIs are affected:
- [`LoadFromXaml` extension methods](https://learn.microsoft.com/en-us/dotnet/maui/xaml/runtime-load) will throw runtime exceptions.
- [Disabling XAML compilation](https://learn.microsoft.com/en-us/dotnet/maui/xaml/xamlc#disable-xaml-compilation) using `[XamlCompilation(XamlCompilationOptions.Skip)]` on pages and controls or whole assemblies will cause runtime exceptions.

## MauiEnableIVisualAssemblyScanning

When this feature is not enabled, custom and third party `IVisual` types will not be automatically discovered and registerd.
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,17 @@
<Target Name="_MauiPrepareForILLink" BeforeTargets="PrepareForILLink">
<PropertyGroup>
<MauiXamlRuntimeParsingSupport Condition="'$(MauiXamlRuntimeParsingSupport)' == '' and '$(PublishAot)' == 'true'">false</MauiXamlRuntimeParsingSupport>
<MauiEnableIVisualAssemblyScanning Condition="'$(MauiEnableIVisualAssemblyScanning)' == ''">false</MauiEnableIVisualAssemblyScanning>
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption Include="Microsoft.Maui.RuntimeFeature.IsXamlRuntimeParsingSupported"
Condition="'$(MauiXamlRuntimeParsingSupport)' != ''"
Value="$(MauiXamlRuntimeParsingSupport)"
Trim="true" />
<RuntimeHostConfigurationOption Include="Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled"
Condition="'$(MauiEnableIVisualAssemblyScanning)' != ''"
Value="$(MauiEnableIVisualAssemblyScanning)"
Trim="true" />
</ItemGroup>
</Target>

Expand Down
27 changes: 25 additions & 2 deletions src/Controls/src/Core/Visuals/VisualTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinati
void InitMappings()
{
var mappings = new Dictionary<string, IVisual>(StringComparer.OrdinalIgnoreCase);

if (RuntimeFeature.IsIVisualAssemblyScanningEnabled)
{
ScanAllAssemblies(mappings);
}
else
{
Register(typeof(VisualMarker.MaterialVisual), mappings);
Register(typeof(VisualMarker.DefaultVisual), mappings);
Register(typeof(VisualMarker.MatchParentVisual), mappings);
}

_visualTypeMappings = mappings;
}

[RequiresUnreferencedCode("The IVisual types might be removed by trimming and automatic registration via assembly scanning may not work as expected.")]
void ScanAllAssemblies(Dictionary<string, IVisual> mappings)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

// Check for IVisual Types
Expand All @@ -45,8 +63,6 @@ void InitMappings()
if (Internals.Registrar.ExtraAssemblies != null)
foreach (var assembly in Internals.Registrar.ExtraAssemblies)
RegisterFromAttributes(assembly, mappings);

_visualTypeMappings = mappings;
}

static void RegisterFromAttributes(Assembly assembly, Dictionary<string, IVisual> mappings)
Expand Down Expand Up @@ -138,6 +154,13 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c
if (_visualTypeMappings.TryGetValue(strValue, out IVisual returnValue))
return returnValue;

if (!RuntimeFeature.IsIVisualAssemblyScanningEnabled)
{
Application.Current?.FindMauiContext()?.CreateLogger<IVisual>()?.LogWarning(
"Unable to find visual {key}. Automatic discovery of IVisual types is disabled. You can enabled it by setting the $(MauiEnableIVisualAssemblyScanning)=true MSBuild property. " +
"Note: automatic registration of IVisual types through assembly scanning is not trimming-compatible and it can lead to slower app startup.", strValue);
}

return VisualMarker.Default;
}

Expand Down
2 changes: 2 additions & 0 deletions src/Core/src/ILLink.Substitutions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<type fullname="Microsoft.Maui.RuntimeFeature">
<method signature="System.Boolean get_IsXamlRuntimeParsingSupported()" body="stub" feature="Microsoft.Maui.RuntimeFeature.IsXamlRuntimeParsingSupported" value="false" featurevalue="false" />
<method signature="System.Boolean get_IsXamlRuntimeParsingSupported()" body="stub" feature="Microsoft.Maui.RuntimeFeature.IsXamlRuntimeParsingSupported" value="true" featurevalue="true" />
<method signature="System.Boolean get_IsIVisualAssemblyScanningEnabled()" body="stub" feature="Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled" value="false" featurevalue="false" />
<method signature="System.Boolean get_IsIVisualAssemblyScanningEnabled()" body="stub" feature="Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled" value="true" featurevalue="true" />
</type>
</assembly>
</linker>
6 changes: 6 additions & 0 deletions src/Core/src/RuntimeFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,16 @@ namespace Microsoft.Maui
internal static class RuntimeFeature
{
private const bool IsXamlRuntimeParsingSupportedByDefault = true;
private const bool IsIVisualAssemblyScanningEnabledByDefault = false;

internal static bool IsXamlRuntimeParsingSupported
=> AppContext.TryGetSwitch("Microsoft.Maui.RuntimeFeature.IsXamlRuntimeParsingSupported", out bool isEnabled)
? isEnabled
: IsXamlRuntimeParsingSupportedByDefault;

internal static bool IsIVisualAssemblyScanningEnabled =>
AppContext.TryGetSwitch("Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled", out bool isEnabled)
? isEnabled
: IsIVisualAssemblyScanningEnabledByDefault;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void RunOniOS(string id, string config, string framework, string runtimeI
buildProps.Add("PublishAotUsingRuntimePack=true"); // TODO: This parameter will become obsolete https://github.com/dotnet/runtime/issues/87060
buildProps.Add("_IsPublishing=true"); // using dotnet build with -p:_IsPublishing=true enables targeting simulators
buildProps.Add($"RuntimeIdentifier={runtimeIdentifier}");
buildProps.Add("IlcTreatWarningsAsErrors=false"); // TODO: Remove this once all warnings are fixed https://github.com/dotnet/maui/issues/19397
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this!
I will create a separate PR for all IlcTreatWarningsAsErrors=false in net8.0 branch as a follow-up, as we might backport this feature to net8.0 on the dotnet/runtime side.

}

Assert.IsTrue(DotnetInternal.Build(projectFile, config, framework: $"{framework}-ios", properties: buildProps),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,29 +225,6 @@ public static void AssertWarnings(this List<WarningsPerFile> actualWarnings, Lis
}
},
new WarningsPerFile
{
File = "src/Controls/src/Core/Visuals/VisualTypeConverter.cs",
WarningsPerCode = new List<WarningsPerCode>
{
new WarningsPerCode
{
Code = "IL2026",
Messages = new List<string>
{
"Microsoft.Maui.Controls.VisualTypeConverter.Register(Assembly,Dictionary`2<String,IVisual>): Using member 'System.Reflection.Assembly.GetExportedTypes()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed.",
}
},
new WarningsPerCode
{
Code = "IL2062",
Messages = new List<string>
{
"Microsoft.Maui.Controls.VisualTypeConverter.Register(Assembly,Dictionary`2<String,IVisual>): Value passed to parameter '' of method 'Microsoft.Maui.Controls.VisualTypeConverter.Register(Type,Dictionary`2<String,IVisual>)' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.",
}
},
}
},
new WarningsPerFile
{
File = "src/Core/src/Hosting/Internal/MauiFactory.cs",
WarningsPerCode = new List<WarningsPerCode>
Expand Down
Loading