From 1297bf0ebf40e7574fa0684f680a88bb1fd3b562 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 10 Jul 2024 16:46:11 -0500 Subject: [PATCH 1/5] [Microsoft.Android.Sdk.ILLink] preserve types with `IJniNameProviderAttribute` Fixes: https://github.com/dotnet/android/issues/8940 Context: https://github.com/TobiasBuchholz/Plugin.Firebase/issues/144 Using the NuGet package: Includes a service: namespace Plugin.Firebase.CloudMessaging.Platforms.Android; [Service(Exported = true)] [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })] public class MyFirebaseMessagingService : FirebaseMessagingService Unfortunately, using `TrimMode=full` completely trims away the above service, which is required for push notifications to work. I could reproduce this problem in a test using the above NuGet package. To fix this, we can modify `MarkJavaObjects` to preserve types with attributes that implement `Java.Interop.IJniNameProviderAttribute`, and the new test now passes. --- .../MarkJavaObjects.cs | 37 +++++++++++++++++-- .../Tasks/LinkerTests.cs | 34 +++++++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs b/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs index 290f45a70e6..416027f4f19 100644 --- a/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs +++ b/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs @@ -4,9 +4,9 @@ using Mono.Cecil; using Mono.Linker; using Mono.Linker.Steps; -using Mono.Tuner; using Java.Interop.Tools.Cecil; using Xamarin.Android.Tasks; +using Profile = Microsoft.Android.Sdk.ILLink.Profile; namespace MonoDroid.Tuner { @@ -27,7 +27,14 @@ public override void Initialize (LinkContext context, MarkContext markContext) bool IsActiveFor (AssemblyDefinition assembly) { - return assembly.MainModule.HasTypeReference ("System.Net.Http.HttpMessageHandler") || assembly.MainModule.HasTypeReference ("Android.Util.IAttributeSet"); + if (Profile.IsSdkAssembly (assembly)) + return false; + if (Profile.IsProductAssembly (assembly)) + return false; + + return assembly.MainModule.HasTypeReference ("System.Net.Http.HttpMessageHandler") || + assembly.MainModule.HasTypeReference ("Java.Lang.Object") || + assembly.MainModule.HasTypeReference ("Android.Util.IAttributeSet"); } public void ProcessAssembly (AssemblyDefinition assembly, string androidHttpClientHandlerType, Dictionary> customViewMap) @@ -47,16 +54,40 @@ public void ProcessAssembly (AssemblyDefinition assembly, string androidHttpClie } } - // Custom views in Android .xml files + // Continue if not an IJavaObject if (!type.ImplementsIJavaObject (cache)) continue; + + // Custom views in Android .xml files if (customViewMap.ContainsKey (type.FullName)) { Annotations.Mark (type); PreserveJavaObjectImplementation (type); + continue; + } + + // Types with Java.Interop.IJniNameProviderAttribute attributes + if (ShouldPreserveBasedOnAttributes (type)) { + Annotations.Mark (type); + PreserveJavaObjectImplementation (type); + continue; } } } + bool ShouldPreserveBasedOnAttributes (TypeDefinition type) + { + if (!type.HasCustomAttributes) + return false; + + foreach (var attr in type.CustomAttributes) { + if (attr.AttributeType.Implements ("Java.Interop.IJniNameProviderAttribute", cache)) { + return true; + } + } + + return false; + } + public void ProcessType (TypeDefinition type) { // If this isn't a JLO or IJavaObject implementer, 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 d91ed72976f..2be89006b6a 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 @@ -598,6 +598,40 @@ public void PreserveIX509TrustManagerSubclasses ([Values(true, false)] bool hasS } } + [Test] + public void PreserveServices () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + TrimModeRelease = TrimMode.Full, + PackageReferences = { + new Package { Id = "Plugin.Firebase.CloudMessaging", Version = "3.0.0" }, + } + }; + proj.MainActivity = proj.DefaultMainActivity + .Replace ("//${FIELDS}", + """ + protected override void OnNewIntent(Android.Content.Intent? intent) + { + base.OnNewIntent(intent); + Plugin.Firebase.CloudMessaging.FirebaseCloudMessagingImplementation.OnNewIntent(intent); + } + """) + .Replace ("//${AFTER_ONCREATE}", "Plugin.Firebase.Core.Platforms.Android.CrossFirebase.Initialize (this);"); + + using var b = CreateApkBuilder (); + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + + var assemblyPath = BuildTest.GetLinkedPath (b, isRelease: true, "Plugin.Firebase.CloudMessaging.dll"); + FileAssert.Exists (assemblyPath); + using var assembly = AssemblyDefinition.ReadAssembly (assemblyPath); + var types = new [] { "Plugin.Firebase.CloudMessaging.Platforms.Android.MyFirebaseMessagingService" }; + foreach (var typeName in types) { + var td = assembly.MainModule.GetType (typeName); + Assert.IsNotNull (td, $"{typeName} should not have been linked out!"); + } + } + [Test] public void DoNotErrorOnPerArchJavaTypeDuplicates ([Values(true, false)] bool enableMarshalMethods) { From e1afd732d5a3e82c2479c032e74a0e26a61e7e5e Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 11 Jul 2024 11:16:46 -0500 Subject: [PATCH 2/5] formatting --- .../Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 2be89006b6a..134697f8c27 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 @@ -611,10 +611,10 @@ public void PreserveServices () proj.MainActivity = proj.DefaultMainActivity .Replace ("//${FIELDS}", """ - protected override void OnNewIntent(Android.Content.Intent? intent) + protected override void OnNewIntent (Android.Content.Intent? intent) { - base.OnNewIntent(intent); - Plugin.Firebase.CloudMessaging.FirebaseCloudMessagingImplementation.OnNewIntent(intent); + base.OnNewIntent (intent); + Plugin.Firebase.CloudMessaging.FirebaseCloudMessagingImplementation.OnNewIntent (intent); } """) .Replace ("//${AFTER_ONCREATE}", "Plugin.Firebase.Core.Platforms.Android.CrossFirebase.Initialize (this);"); From 49b46e37752d204d4d65d8f565330815bdb0449d Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 11 Jul 2024 13:39:52 -0500 Subject: [PATCH 3/5] Update BuildReleaseArm64XFormsDotNet.apkdesc --- .../BuildReleaseArm64XFormsDotNet.apkdesc | 90 ++++++++++++------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index fa599195f71..001010c276c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -5,7 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9173020 + "Size": 9192544 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -35,13 +35,13 @@ "Size": 8330 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 77620 + "Size": 78485 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 500856 + "Size": 651851 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5319 + "Size": 5306 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 4356 @@ -122,7 +122,7 @@ "Size": 9990 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 932380 + "Size": 932615 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { "Size": 199662 @@ -167,61 +167,82 @@ "Size": 2186 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 5005 + "Size": 5007 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { - "Size": 17872 + "Size": 25440 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.AppCompatResources.dll.so": { - "Size": 7425 + "Size": 25229 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.dll.so": { - "Size": 146152 + "Size": 277525 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CardView.dll.so": { - "Size": 7469 + "Size": 8459 + }, + "lib/arm64-v8a/lib_Xamarin.AndroidX.Collection.dll.so": { + "Size": 21036 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CoordinatorLayout.dll.so": { - "Size": 18823 + "Size": 20161 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Core.dll.so": { - "Size": 134318 + "Size": 359963 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CursorAdapter.dll.so": { - "Size": 10076 + "Size": 16269 + }, + "lib/arm64-v8a/lib_Xamarin.AndroidX.CustomView.dll.so": { + "Size": 19201 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.DrawerLayout.dll.so": { - "Size": 16856 + "Size": 16904 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Fragment.dll.so": { - "Size": 55435 + "Size": 79136 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Legacy.Support.Core.UI.dll.so": { - "Size": 6806 + "Size": 7341 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Lifecycle.Common.dll.so": { - "Size": 7982 + "Size": 16519 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Lifecycle.LiveData.Core.dll.so": { - "Size": 7770 + "Size": 8165 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Lifecycle.ViewModel.dll.so": { - "Size": 8114 + "Size": 14378 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Loader.dll.so": { - "Size": 14499 + "Size": 18542 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.RecyclerView.dll.so": { - "Size": 95162 + "Size": 128026 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SavedState.dll.so": { - "Size": 6050 + "Size": 8318 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SwipeRefreshLayout.dll.so": { - "Size": 14858 + "Size": 19641 + }, + "lib/arm64-v8a/lib_Xamarin.AndroidX.Transition.dll.so": { + "Size": 35272 + }, + "lib/arm64-v8a/lib_Xamarin.AndroidX.VectorDrawable.Animated.dll.so": { + "Size": 12156 + }, + "lib/arm64-v8a/lib_Xamarin.AndroidX.VectorDrawable.dll.so": { + "Size": 9517 + }, + "lib/arm64-v8a/lib_Xamarin.AndroidX.VersionedParcelable.dll.so": { + "Size": 31298 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager.dll.so": { - "Size": 20961 + "Size": 23191 + }, + "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager2.dll.so": { + "Size": 12627 }, "lib/arm64-v8a/lib_Xamarin.Forms.Core.dll.so": { "Size": 563905 @@ -236,7 +257,16 @@ "Size": 63542 }, "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { - "Size": 67675 + "Size": 359816 + }, + "lib/arm64-v8a/lib_Xamarin.Google.Guava.ListenableFuture.dll.so": { + "Size": 6001 + }, + "lib/arm64-v8a/lib_Xamarin.Kotlin.StdLib.dll.so": { + "Size": 450339 + }, + "lib/arm64-v8a/lib_Xamarin.KotlinX.Coroutines.Core.Jvm.dll.so": { + "Size": 117470 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 1562 @@ -263,7 +293,7 @@ "Size": 159544 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 349520 + "Size": 551688 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -416,10 +446,10 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { - "Size": 98577 + "Size": 99858 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -446,7 +476,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98450 + "Size": 99731 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2486,5 +2516,5 @@ "Size": 812848 } }, - "PackageSize": 10521867 + "PackageSize": 11874565 } \ No newline at end of file From 36d58ae9cc8686934a6dc12148188f151ca61995 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 11 Jul 2024 14:06:52 -0500 Subject: [PATCH 4/5] Revert "Update BuildReleaseArm64XFormsDotNet.apkdesc" This reverts commit 49b46e37752d204d4d65d8f565330815bdb0449d. --- .../BuildReleaseArm64XFormsDotNet.apkdesc | 90 +++++++------------ 1 file changed, 30 insertions(+), 60 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index 001010c276c..fa599195f71 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -5,7 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9192544 + "Size": 9173020 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -35,13 +35,13 @@ "Size": 8330 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 78485 + "Size": 77620 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 651851 + "Size": 500856 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 5306 + "Size": 5319 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 4356 @@ -122,7 +122,7 @@ "Size": 9990 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 932615 + "Size": 932380 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { "Size": 199662 @@ -167,82 +167,61 @@ "Size": 2186 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 5007 + "Size": 5005 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { - "Size": 25440 + "Size": 17872 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.AppCompatResources.dll.so": { - "Size": 25229 + "Size": 7425 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.AppCompat.dll.so": { - "Size": 277525 + "Size": 146152 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CardView.dll.so": { - "Size": 8459 - }, - "lib/arm64-v8a/lib_Xamarin.AndroidX.Collection.dll.so": { - "Size": 21036 + "Size": 7469 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CoordinatorLayout.dll.so": { - "Size": 20161 + "Size": 18823 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Core.dll.so": { - "Size": 359963 + "Size": 134318 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.CursorAdapter.dll.so": { - "Size": 16269 - }, - "lib/arm64-v8a/lib_Xamarin.AndroidX.CustomView.dll.so": { - "Size": 19201 + "Size": 10076 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.DrawerLayout.dll.so": { - "Size": 16904 + "Size": 16856 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Fragment.dll.so": { - "Size": 79136 + "Size": 55435 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Legacy.Support.Core.UI.dll.so": { - "Size": 7341 + "Size": 6806 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Lifecycle.Common.dll.so": { - "Size": 16519 + "Size": 7982 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Lifecycle.LiveData.Core.dll.so": { - "Size": 8165 + "Size": 7770 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Lifecycle.ViewModel.dll.so": { - "Size": 14378 + "Size": 8114 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Loader.dll.so": { - "Size": 18542 + "Size": 14499 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.RecyclerView.dll.so": { - "Size": 128026 + "Size": 95162 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SavedState.dll.so": { - "Size": 8318 + "Size": 6050 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.SwipeRefreshLayout.dll.so": { - "Size": 19641 - }, - "lib/arm64-v8a/lib_Xamarin.AndroidX.Transition.dll.so": { - "Size": 35272 - }, - "lib/arm64-v8a/lib_Xamarin.AndroidX.VectorDrawable.Animated.dll.so": { - "Size": 12156 - }, - "lib/arm64-v8a/lib_Xamarin.AndroidX.VectorDrawable.dll.so": { - "Size": 9517 - }, - "lib/arm64-v8a/lib_Xamarin.AndroidX.VersionedParcelable.dll.so": { - "Size": 31298 + "Size": 14858 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager.dll.so": { - "Size": 23191 - }, - "lib/arm64-v8a/lib_Xamarin.AndroidX.ViewPager2.dll.so": { - "Size": 12627 + "Size": 20961 }, "lib/arm64-v8a/lib_Xamarin.Forms.Core.dll.so": { "Size": 563905 @@ -257,16 +236,7 @@ "Size": 63542 }, "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { - "Size": 359816 - }, - "lib/arm64-v8a/lib_Xamarin.Google.Guava.ListenableFuture.dll.so": { - "Size": 6001 - }, - "lib/arm64-v8a/lib_Xamarin.Kotlin.StdLib.dll.so": { - "Size": 450339 - }, - "lib/arm64-v8a/lib_Xamarin.KotlinX.Coroutines.Core.Jvm.dll.so": { - "Size": 117470 + "Size": 67675 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 1562 @@ -293,7 +263,7 @@ "Size": 159544 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 551688 + "Size": 349520 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -446,10 +416,10 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 99858 + "Size": 98577 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -476,7 +446,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 99731 + "Size": 98450 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2516,5 +2486,5 @@ "Size": 812848 } }, - "PackageSize": 11874565 + "PackageSize": 10521867 } \ No newline at end of file From c4bffbd4df34210f54638e6daa92204f3bdb49a1 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 11 Jul 2024 14:08:53 -0500 Subject: [PATCH 5/5] Ignore Android.Runtime.RegisterAttribute! --- src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs b/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs index 416027f4f19..bb029b7421a 100644 --- a/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs +++ b/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs @@ -80,6 +80,10 @@ bool ShouldPreserveBasedOnAttributes (TypeDefinition type) return false; foreach (var attr in type.CustomAttributes) { + // Ignore Android.Runtime.RegisterAttribute + if (attr.AttributeType.FullName == "Android.Runtime.RegisterAttribute") { + continue; + } if (attr.AttributeType.Implements ("Java.Interop.IJniNameProviderAttribute", cache)) { return true; }