Skip to content

Commit a79ad46

Browse files
authored
Merge pull request #320 from winnerspiros/copilot/fix-osu-apk-crash-on-startup-again
fix(android): correct framework assembly names in Linker.xml to prevent startup crash
2 parents 7e55331 + cff0238 commit a79ad46

2 files changed

Lines changed: 29 additions & 10 deletions

File tree

osu.Android/Linker.xml

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,39 @@
6262
<!-- ═══════════════════════════════════════════════════════════════════════
6363
ppy framework
6464
═══════════════════════════════════════════════════════════════════════
65-
ppy.osu.Framework: DrawableComponentLookup and SourceGeneratedImplementationLookup
65+
osu.Framework: DrawableComponentLookup and SourceGeneratedImplementationLookup
6666
use Type.GetType()/Activator.CreateInstance() for draw hierarchy resolution.
6767
Shader attribute scanning, TextureLoaderStore fallback chain, bindable system,
6868
resource store extension routing — all reflection-dependent.
69-
ppy.osu.Framework.Android: Android-specific host, input handling, surface wrappers.
69+
osu.Framework.Android: Android-specific host, input handling, surface wrappers.
7070
AndroidGameActivity carries the (IntPtr, JniHandleOwnership) JNI-activation
7171
constructor and RegisterAttribute-driven type-binding needed for all derived
7272
Activity/Fragment types. Without preserve="all", ILLink will trim these
7373
constructors (they are only reachable via JNI, not through any managed call
7474
graph), causing TypeManager.Activate to throw NotSupportedException:
7575
"Could not activate JNI Handle ... as managed type 'osu.Android.OsuGameActivity'"
76-
at startup — exactly the crash reported in the 2026.508.222 field log.
76+
at startup.
7777
ppy.Veldrid.SPIRV: SPIR-V cross-compiler; dynamically loads shader reflector types.
78+
(NuGet package ID and assembly name are both ppy.Veldrid.SPIRV — no mismatch.)
7879
79-
NOTE: ppy.osu.Framework and ppy.osu.Framework.Android originate from net10.0
80-
NuGet packages and are not visible in ILLink's assembly search path at descriptor-
80+
IMPORTANT — assembly name vs. NuGet package ID:
81+
ILLink's <assembly fullname="..."> descriptor element matches against the CLR
82+
assembly name (i.e. the value of <AssemblyName> in the project file), NOT the
83+
NuGet package ID. These two values are NOT always the same. In particular:
84+
NuGet package ID → CLR assembly name (AssemblyName in csproj)
85+
ppy.osu.Framework → osu.Framework
86+
ppy.osu.Framework.Android → osu.Framework.Android
87+
ppy.Veldrid.SPIRV → ppy.Veldrid.SPIRV (same — no ppy. mismatch here)
88+
Using the NuGet package ID instead of the assembly name causes the preserve rule
89+
to be stored but never matched: ILLink looks for an assembly named
90+
"ppy.osu.Framework.Android" in the link set, finds only "osu.Framework.Android",
91+
skips preservation, and freely trims the JNI-activation constructor from
92+
AndroidGameActivity. The resulting startup crash ("Could not activate JNI Handle
93+
... as managed type 'osu.Android.OsuGameActivity'") is exactly what was reported
94+
in the v2026.508.225 field log.
95+
96+
NOTE: osu.Framework and osu.Framework.Android originate from net10.0 NuGet
97+
packages and are not visible in ILLink's assembly search path at descriptor-
8198
processing time. ILLink therefore emits warning IL2007 ("Could not resolve
8299
assembly") for each entry. This warning is BENIGN and EXPECTED: ILLink stores
83100
the preserve="all" rule in its internal table even when it cannot resolve the
@@ -86,9 +103,9 @@
86103
the stored rule and preserves the assembly in full. Removing these entries
87104
"to silence the warnings" allows ILLink to freely trim JNI-only constructors
88105
from AndroidGameActivity, crashing the app on launch. -->
89-
<assembly fullname="ppy.osu.Framework" preserve="all" />
90-
<assembly fullname="ppy.osu.Framework.Android" preserve="all" />
91-
<assembly fullname="ppy.Veldrid.SPIRV" preserve="all" />
106+
<assembly fullname="osu.Framework" preserve="all" />
107+
<assembly fullname="osu.Framework.Android" preserve="all" />
108+
<assembly fullname="ppy.Veldrid.SPIRV" preserve="all" />
92109

93110
<!-- ═══════════════════════════════════════════════════════════════════════
94111
Audio (ManagedBass)

osu.Android/OsuGameActivity.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ namespace osu.Android
2727
// Declare ScreenOrientation in the manifest (rather than only assigning RequestedOrientation
2828
// at runtime in OnCreate) so Android creates the activity in landscape from the very first
2929
// frame — the SurfaceView is sized correctly on creation and there is no orientation-change
30-
// event during startup. This is defensive hardening alongside the main fix in osu.Android.props
31-
// (disabling trimming + profiled AOT, which was the actual cause of the startup crash).
30+
// event during startup. This is defensive hardening alongside the linker fix in
31+
// osu.Android/Linker.xml (using correct CLR assembly names osu.Framework /
32+
// osu.Framework.Android instead of the NuGet package IDs ppy.osu.Framework /
33+
// ppy.osu.Framework.Android, which was the actual cause of the startup crash).
3234
[Activity(ResizeableActivity = true, ScreenOrientation = ScreenOrientation.Landscape, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode | ConfigChanges.SmallestScreenSize | ConfigChanges.ScreenLayout | ConfigChanges.ColorMode | ConfigChanges.Density | ConfigChanges.Touchscreen | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.Navigation, Exported = true, LaunchMode = DEFAULT_LAUNCH_MODE, MainLauncher = true)]
3335
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\.osz", DataHost = "*", DataMimeType = "*/*")]
3436
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\.osk", DataHost = "*", DataMimeType = "*/*")]

0 commit comments

Comments
 (0)