From 7840072317e0436b5b50e33d6f7d25f0349a297d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 9 May 2026 09:44:13 +0000
Subject: [PATCH 1/6] fix: add SDL3-CS to Linker.xml + AndroidLinkSkip to stop
OsuGameActivity JNI activation crash
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/3e3e344a-127e-4c51-b475-cfaa53791766
Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
---
osu.Android.props | 13 +++++++
osu.Android/Linker.xml | 63 ++++++++++++++++------------------
osu.Android/OsuGameActivity.cs | 16 ++++++---
3 files changed, 54 insertions(+), 38 deletions(-)
diff --git a/osu.Android.props b/osu.Android.props
index 5c20ca86fc6b..db49b3d40316 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -112,6 +112,19 @@
we make it explicit so a future SDK bump cannot silently start stripping IL
and reproduce the trim-then-AOT crash class we removed above. -->
false
+
+ $(AndroidLinkSkip);osu.Framework.Android;SDL3-CS
diff --git a/osu.Android/Linker.xml b/osu.Android/Linker.xml
index 3325da1c3c4f..5618e5b60223 100644
--- a/osu.Android/Linker.xml
+++ b/osu.Android/Linker.xml
@@ -67,13 +67,24 @@
Shader attribute scanning, TextureLoaderStore fallback chain, bindable system,
resource store extension routing — all reflection-dependent.
osu.Framework.Android: Android-specific host, input handling, surface wrappers.
- AndroidGameActivity carries the (IntPtr, JniHandleOwnership) JNI-activation
- constructor and RegisterAttribute-driven type-binding needed for all derived
- Activity/Fragment types. Without preserve="all", ILLink will trim these
- constructors (they are only reachable via JNI, not through any managed call
- graph), causing TypeManager.Activate to throw NotSupportedException:
+ AndroidGameActivity is the abstract base of OsuGameActivity but does NOT declare
+ its own (IntPtr, JniHandleOwnership) JNI-activation constructor — that constructor
+ lives on its SDLActivity grandparent (in the SDL3-CS assembly, listed below).
+ Without preserve="all", ILLink trims reflection-only members such as
+ RegisterAttribute-driven type-binding and generated JNI glue — none of which have
+ a managed call-graph path.
+ SDL3-CS (ppy.SDL3-CS): Contains Org.Libsdl.App.SDLActivity, the Java-binding class
+ from which AndroidGameActivity (and transitively OsuGameActivity) inherits.
+ SDLActivity's JNI-activation constructors — in particular the
+ (IntPtr, JniHandleOwnership) overload used by TypeManager.Activate to wrap the
+ freshly-created Android Activity Java object in a managed peer — are never called
+ from managed code, so ILLink has no static call-graph path to them and strips them
+ under AndroidLinkMode=Full. The resulting crash is exactly the
"Could not activate JNI Handle ... as managed type 'osu.Android.OsuGameActivity'"
- at startup.
+ NotSupportedException seen in the v2026.508.226 and v2026.508.228 field logs.
+ (The v2026.508.228 fix added osu.Framework.Android to Linker.xml and a
+ [DynamicDependency] on OsuGameActivity() but missed SDL3-CS entirely, because the
+ assumption was that AndroidGameActivity carried the JNI ctor — it does not.)
ppy.Veldrid.SPIRV: SPIR-V cross-compiler; dynamically loads shader reflector types.
(NuGet package ID and assembly name are both ppy.Veldrid.SPIRV — no mismatch.)
@@ -84,38 +95,24 @@
NuGet package ID → CLR assembly name (AssemblyName in csproj)
ppy.osu.Framework → osu.Framework
ppy.osu.Framework.Android → osu.Framework.Android
+ ppy.SDL3-CS → SDL3-CS
ppy.Veldrid.SPIRV → ppy.Veldrid.SPIRV (same — no ppy. mismatch here)
- Using the NuGet package ID instead of the assembly name causes the preserve rule
- to be stored but never matched: ILLink looks for an assembly named
- "ppy.osu.Framework.Android" in the link set, finds only "osu.Framework.Android",
- skips preservation, and freely trims the JNI-activation constructor from
- AndroidGameActivity. The resulting startup crash ("Could not activate JNI Handle
- ... as managed type 'osu.Android.OsuGameActivity'") is exactly what was reported
- in the v2026.508.225 field log.
+ Using the NuGet package ID instead of the CLR assembly name causes the preserve rule
+ to be stored but never matched.
- NOTE: osu.Framework and osu.Framework.Android originate from net10.0 NuGet
+ NOTE: osu.Framework, osu.Framework.Android, and SDL3-CS originate from NuGet
packages and are not visible in ILLink's assembly search path at descriptor-
- processing time. ILLink therefore emits warning IL2007 ("Could not resolve
- assembly") for each entry. This warning is BENIGN and EXPECTED: ILLink stores
- the preserve="all" rule in its internal table even when it cannot resolve the
- assembly immediately. When the assembly is later encountered during the trimming
- pass (where the .NET Android SDK does include it in the link set), ILLink finds
- the stored rule and preserves the assembly in full. Removing these entries
- "to silence the warnings" allows ILLink to freely trim JNI-only constructors
- from AndroidGameActivity, crashing the app on launch.
-
- ADDITIONAL DEFENCE (v2026.508.228+): OsuGameActivity carries a [DynamicDependency]
- attribute that explicitly roots AndroidGameActivity's constructors from the
- osu.Android assembly. Because osu.Android is unambiguously preserve="all" and is
- always resolvable at descriptor-processing time, ILLink processes this root
- reference before it can trim the JNI-activation constructor, regardless of whether
- the IL2007-deferred rule for osu.Framework.Android is honoured. This supersedes
- the v2026.508.227 approach (explicit OsuGameActivity(IntPtr, JniHandleOwnership)
- constructor) which did not compile because AndroidGameActivity does not expose an
- explicit (IntPtr, JniHandleOwnership) constructor — only its SDLActivity grandparent
- does, and C# base() invocations resolve only against the direct parent class. -->
+ processing time, causing IL2007 ("Could not resolve assembly") for each entry.
+ In theory ILLink stores the rule for later application; in practice the deferred
+ mechanism has proven unreliable with ILLink 10.0.x + NuGet-resolved assemblies
+ (evidenced by the v2026.508.228 field crash being identical to v2026.508.226 despite
+ these entries being present). The primary protection is therefore AndroidLinkSkip
+ in osu.Android.props, which bypasses ILLink entirely for these assemblies; these
+ Linker.xml entries and the [DynamicDependency] attributes on OsuGameActivity serve
+ as secondary and tertiary backstops respectively. -->
+
-
+
+
+ NU1902
+
From bc3c98ede5f903a2f2dd6e9adf297c2642e841b0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 9 May 2026 10:04:40 +0000
Subject: [PATCH 3/6] =?UTF-8?q?chore:=20update=20SharpCompress=200.47.3=20?=
=?UTF-8?q?=E2=86=92=200.48.0,=20remove=20obsolete=20NU1902=20suppression?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/29c65f29-ab61-4fc1-8533-85179a4caf15
Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
---
osu.Game/osu.Game.csproj | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index b1d79ef0a450..15eea8db21b1 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -51,13 +51,7 @@
-
-
-
- NU1902
-
+
From 2fcc72e68695fe5470d57739d6a5cc730c066586 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 9 May 2026 10:12:19 +0000
Subject: [PATCH 4/6] chore: update all dependencies across codebase and
workflows
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/d5f7d66b-e601-4c64-8929-91a628166bc5
Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
---
.github/workflows/ci.yml | 2 +-
Directory.Build.props | 2 +-
.../osu.Game.Rulesets.EmptyFreeform.Tests.csproj | 4 ++--
.../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 ++--
...osu.Game.Rulesets.EmptyScrolling.Tests.csproj | 4 ++--
.../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 ++--
osu.Android/osu.Android.csproj | 2 +-
osu.Desktop/osu.Desktop.csproj | 4 ++--
osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 2 +-
.../osu.Game.Rulesets.Catch.Tests.csproj | 4 ++--
.../osu.Game.Rulesets.Mania.Tests.csproj | 4 ++--
.../osu.Game.Rulesets.Osu.Tests.iOS.csproj | 2 +-
.../osu.Game.Rulesets.Osu.Tests.csproj | 4 ++--
.../osu.Game.Rulesets.Taiko.Tests.csproj | 4 ++--
.../osu.Game.Tests.Android.csproj | 2 +-
osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj | 2 +-
osu.Game.Tests/osu.Game.Tests.csproj | 4 ++--
.../osu.Game.Tournament.Tests.csproj | 4 ++--
osu.Game/osu.Game.csproj | 16 ++++++++--------
osu.iOS/osu.iOS.csproj | 2 +-
20 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 556441b4b48a..cc787db7a51d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -106,7 +106,7 @@ jobs:
exit $exit_code
- name: InspectCode
- uses: JetBrains/ReSharper-InspectCode@v0.12
+ uses: JetBrains/ReSharper-InspectCode@v0.13
with:
tool-version: 2026.1.0.1
# this is WTF tier but if you don't specify *both* of these the defaults assume `build: true`
diff --git a/Directory.Build.props b/Directory.Build.props
index 607ee1ed9e33..587085384613 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -20,7 +20,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
index b671686c89aa..a9bb1e73643a 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
@@ -9,8 +9,8 @@
false
-
-
+
+
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 796f182a2561..e9529b4328c2 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -9,8 +9,8 @@
false
-
-
+
+
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
index 2ff812335eac..dd2186a7eaad 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
@@ -9,8 +9,8 @@
false
-
-
+
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 796f182a2561..e9529b4328c2 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -9,8 +9,8 @@
false
-
-
+
+
diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj
index 26f147124053..66bb1a80a764 100644
--- a/osu.Android/osu.Android.csproj
+++ b/osu.Android/osu.Android.csproj
@@ -18,7 +18,7 @@
-
+
-
+
diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
index b2170ee51027..fe4ca4c79233 100644
--- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
+++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 388802aaaa22..016868d2742d 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index 315c1662b4e9..e9e5d0a18375 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
index c2f34683a4bd..6aa9e6fa9b17 100644
--- a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
index e259e9847f9e..c3515c87754e 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -1,9 +1,9 @@
-
+
-
+
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index ae742a661343..f5f7c0e6c182 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
index fe55f652bfc5..c453b14b3b3f 100644
--- a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
+++ b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
@@ -29,7 +29,7 @@
-
+
-
+
-
-
+
+
diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj
index 3d897f0ef0f7..2b81c0e7b554 100644
--- a/osu.iOS/osu.iOS.csproj
+++ b/osu.iOS/osu.iOS.csproj
@@ -20,7 +20,7 @@
-
+
From b7decbe4a87f8a22e91c92cedb3330ca9c858550 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 9 May 2026 10:13:33 +0000
Subject: [PATCH 5/6] chore: fix stale framework version comment in
osu.Game.csproj
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/d5f7d66b-e601-4c64-8929-91a628166bc5
Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
---
osu.Game/osu.Game.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index a64cf62aa0d6..7fb0ae1ff102 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -41,7 +41,7 @@
-
+