Skip to content

Commit

Permalink
[One .NET] fix remaining Mono.Android.dll linker warnings
Browse files Browse the repository at this point in the history
Fixes: dotnet#5652

There are two remaining linker warnings when building with:

    > dotnet build -c Release -p:SuppressTrimAnalysisWarnings=false
    ...
    src\Mono.Android\Android.Runtime\ResourceIdManager.cs(37,6): warning IL2026: Android.Runtime.ResourceIdManager.GetResourceTypeFromAssembly(Assembly): Using method 'System.Reflection.Assembly.GetType(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed.
    src\Mono.Android\Java.Interop\JavaObjectExtensions.cs(136,4): warning IL2026: Java.Interop.JavaObjectExtensions.GetHelperType(Type,String): Using method 'System.Reflection.Assembly.GetType(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed.
    src\Mono.Android\Java.Interop\JavaObjectExtensions.cs(131,5): warning IL2026: Java.Interop.JavaObjectExtensions.GetHelperType(Type,String): Using method 'System.Reflection.Assembly.GetType(String)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed.

The two issues here:

1. `ResourceIdManager` uses reflection for the implementation of
   `Resource.designer.cs`. Specify `UnconditionalSuppressMessage` to
   ignore the warning, because the assembly hitting the warning is the
   "root assembly". The methods in question will not be removed by the
   linker.

2. `JavaObjectExtensions.GetHelperType` dynamically looks up `Invoker`
   types. Specify `UnconditionalSuppressMessage` to ignore the
   warning, because the `MarkJavaObjects` linker step preserves them.
   Additionally, I renamed the method to `GetInvokerType()` and
   hardcoded `"Invoker"` within the method. This should prevent us
   from messing this up if a new "helper" type is added in addition to
   `Invoker`.

Unfortunately, even after all the issues are solved. `ILLink` still
appears to emit warnings:

    Java.Interop.dll warning IL2104: Assembly 'Java.Interop' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
    Mono.Android.dll warning IL2104: Assembly 'Mono.Android' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries

My guess is that `UnconditionalSuppressMessage` isn't clearing
`IL2104` when it should be. I'll file an issue upstream in mono/linker
about this.
  • Loading branch information
jonathanpeppers committed Sep 7, 2021
1 parent 69c617b commit ea75e92
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/Mono.Android/Android.Runtime/ResourceIdManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

namespace Android.Runtime
Expand Down Expand Up @@ -30,6 +31,7 @@ public static void UpdateIdValues ()
}
}

[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "Types in Resource.designer.cs are preserved, because it is the root assembly passed to the linker.")]
static Type? GetResourceTypeFromAssembly (Assembly assembly)
{
foreach (var customAttribute in assembly.GetCustomAttributes (typeof (ResourceDesignerAttribute), true)) {
Expand Down
10 changes: 6 additions & 4 deletions src/Mono.Android/Java.Interop/JavaObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static IJavaObject CastClass (IJavaObject instance, Type resultType)

if (resultType.IsAbstract) {
// TODO: keep in sync with TypeManager.CreateInstance() algorithm
var invokerType = GetHelperType (resultType, "Invoker");
var invokerType = GetInvokerType (resultType);
if (invokerType == null)
throw new ArgumentException ("Unable to get Invoker for abstract type '" + resultType.FullName + "'.", "TResult");
resultType = invokerType;
Expand Down Expand Up @@ -122,10 +122,12 @@ static IJavaObject CastClass (IJavaObject instance, Type resultType)
instance.GetType ().FullName, resultType.FullName));
}

// typeof(Foo) -> FooSuffix
// typeof(Foo<>) -> FooSuffix`1
internal static Type? GetHelperType (Type type, string suffix)
// typeof(Foo) -> FooInvoker
// typeof(Foo<>) -> FooInvoker`1
[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "*Invoker types are preserved by the MarkJavaObjects linker step.")]
internal static Type? GetInvokerType (Type type)
{
const string suffix = "Invoker";
Type[] arguments = type.GetGenericArguments ();
if (arguments.Length == 0)
return type.Assembly.GetType (type + suffix);
Expand Down
2 changes: 1 addition & 1 deletion src/Mono.Android/Java.Interop/TypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ internal static IJavaPeerable CreateInstance (IntPtr handle, JniHandleOwnership
type = targetType;

if (type.IsInterface || type.IsAbstract) {
var invokerType = JavaObjectExtensions.GetHelperType (type, "Invoker");
var invokerType = JavaObjectExtensions.GetInvokerType (type);
if (invokerType == null)
throw new NotSupportedException ("Unable to find Invoker for type '" + type.FullName + "'. Was it linked away?",
CreateJavaLocationException ());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,25 @@ public Foo ()
[Test]
public void DotNetNew ([Values ("android", "androidlib", "android-bindinglib")] string template)
{
var parameters = new List<string> {
// TODO: Uncomment after warnings are solved
// Java.Interop.dll warning IL2104: Assembly 'Java.Interop' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
// Mono.Android.dll warning IL2104: Assembly 'Mono.Android' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
//"SuppressTrimAnalysisWarnings=false"
};
var dotnet = CreateDotNetBuilder ();
Assert.IsTrue (dotnet.New (template), $"`dotnet new {template}` should succeed");
File.WriteAllBytes (Path.Combine (dotnet.ProjectDirectory, "foo.jar"), ResourceData.JavaSourceJarTestJar);
Assert.IsTrue (dotnet.New ("android-activity"), "`dotnet new android-activity` should succeed");
Assert.IsTrue (dotnet.New ("android-layout", Path.Combine (dotnet.ProjectDirectory, "Resources", "layout")), "`dotnet new android-layout` should succeed");
Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed");

// Debug build
Assert.IsTrue (dotnet.Build (parameters: parameters.ToArray ()), "`dotnet build` should succeed");
dotnet.AssertHasNoWarnings ();

// Release build
parameters.Add ("Configuration=Release");
Assert.IsTrue (dotnet.Build (parameters: parameters.ToArray ()), "`dotnet build` should succeed");
dotnet.AssertHasNoWarnings ();
}

Expand Down

0 comments on commit ea75e92

Please sign in to comment.