Skip to content

Fix Android SIGSEGV at pc=0x0, merge upstream, add keystore upload to release workflow - #219

Merged
winnerspiros merged 6 commits into
masterfrom
copilot/fix-apk-crash-on-startup-again
Apr 20, 2026
Merged

Fix Android SIGSEGV at pc=0x0, merge upstream, add keystore upload to release workflow#219
winnerspiros merged 6 commits into
masterfrom
copilot/fix-apk-crash-on-startup-again

Conversation

Copilot AI commented Apr 20, 2026

Copy link
Copy Markdown

SIGSEGV null function pointer crash on SDLThread ~5s into Android startup. The Vulkan pipeline receives IntPtr.Zero surface handles when the Android native surface isn't ready, passes them through to vkCreateAndroidSurfaceKHR which dereferences a null ANativeWindow*. Separately, DrawThread.OnInitialize() bypasses AndroidGameHost.DrawFrame()'s IsSurfaceReady guard entirely.

Vulkan surface validation (framework submodule)

  • VkSurfaceUtil.cs — validate Surface, JniEnv, and ANativeWindow_fromSurface return before calling into the Vulkan driver
  • VeldridDevice.cs — reject IntPtr.Zero for SurfaceHandle/JniEnvHandle on Android with descriptive exception instead of native crash
  • AndroidGameHost.DrawFrame() — check SurfaceHandle != IntPtr.Zero in addition to IsSurfaceReady (the flag fires from HandleResume() before the surface handle is actually valid)
  • DrawThread.OnInitialize() — wrap BeginFrame/FinishFrame in try-catch; non-fatal on Android when surface isn't ready yet, first regular DrawFrame() handles it
// Before: crashes Vulkan driver with SIGSEGV at pc=0x0
IntPtr aNativeWindow = AndroidRuntime.ANativeWindow_fromSurface(androidSource.JniEnv, androidSource.Surface);
androidSurfaceCi.window = (ANativeWindow*)aNativeWindow; // null

// After: throws managed VeldridException before reaching driver
if (androidSource.Surface == IntPtr.Zero)
    throw new VeldridException("Cannot create Vulkan surface: the Android surface handle is null.");

Upstream merge

Merged 2 commits from ppy/osu master:

Conflict: kept fork's ProjectReference to framework submodule, updated ppy.osu.Game.Resources to 2026.420.0.

Release workflow: optional keystore upload

Added keystore_base64, key_alias, key_password inputs to workflow_dispatch. Users can paste values from SAVE-THESE-SECRETS.txt directly into the "Run workflow" form instead of configuring repo secrets. Priority chain: workflow inputs → repo secrets → auto-generate.


Summary by Gitar

  • Visual refinements:
    • Improved StarRatingSequence UI by using OverlayColourProvider and adding a proxy to fix masking issues.
    • Added a visual test scene TestSceneStarRatingSequence to verify the star rating appearance.
  • Dependencies:
    • Bumped ppy.osu.Game.Resources from 2026.411.0 to 2026.420.0.

This will update automatically on new commits.

Bartłomiej Dach and others added 6 commits April 20, 2026 23:50
…py#37429)

Closes ppy#37406.

I almost applied

```diff
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs
index 318572d..76719a7de8 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs
@@ -5,8 +5,10 @@
 using osu.Framework.Allocation;
 using osu.Framework.Audio;
 using osu.Framework.Audio.Sample;
+using osu.Framework.Extensions.Color4Extensions;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
 using osu.Framework.Graphics.Shapes;
 using osu.Framework.Graphics.Sprites;
 using osu.Framework.Graphics.Transforms;
@@ -134,6 +136,14 @@ private void load(OsuColour colour, AudioManager audio)
                     Anchor = Anchor.BottomLeft,
                     Origin = Anchor.BottomLeft,
                     Colour = colour.ForStarDifficulty(Math.Max(difficulty, 0.1)),
+                    EdgeEffect = difficulty < OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF
+                        ? default
+                        : new EdgeEffectParameters
+                        {
+                            Type = EdgeEffectType.Glow,
+                            Colour = colour.ForStarDifficultyText(difficulty).Opacity((difficulty - OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF) / (10 - OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF) / 2),
+                            Radius = 4
+                        },
                     Height = 0
                 });

```

as a bonus but I'm not that confident in myself.

---------

Co-authored-by: Dean Herbert <pe@ppy.sh>
Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
…g text colour

Merged 2 upstream ppy/osu commits:
- 0ecb892: Update resources (2026.420.0)
- c148e20: Fix illegible star rating text colour in ranked play intro animation (ppy#37429)

Conflict resolution: keep fork's ProjectReference to osu-framework submodule,
update ppy.osu.Game.Resources to 2026.420.0.

Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
…t APK signing

Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/c9e6ebec-a8b6-4aa8-b446-27812ab3b780

Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
… workflow

Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/c9e6ebec-a8b6-4aa8-b446-27812ab3b780

Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
@gitar-bot

gitar-bot Bot commented Apr 20, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

@winnerspiros
winnerspiros marked this pull request as ready for review April 20, 2026 17:25
Copilot AI review requested due to automatic review settings April 20, 2026 17:26
@winnerspiros
winnerspiros merged commit 94df55b into master Apr 20, 2026
2 of 16 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Updates ranked play intro visuals and Android release pipeline ergonomics, alongside bumping the resources package version (PR description also mentions Android Vulkan surface crash hardening in the framework submodule).

Changes:

  • Bump ppy.osu.Game.Resources to 2026.420.0.
  • Adjust StarRatingSequence styling/colouring to use OverlayColourProvider shades and improve high-star text legibility.
  • Add optional keystore-related workflow_dispatch inputs and selection priority logic in release.yml.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

File Description
osu.Game/osu.Game.csproj Bumps resources package version to align with upstream.
osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/StarRatingSequence.cs Uses overlay theme colours and adjusts star-rating text colouring + proxy to avoid masking.
osu.Game.Tests/Visual/RankedPlay/TestSceneStarRatingSequence.cs Adds a visual test scene for basic StarRatingSequence appearance/playback.
.github/workflows/release.yml Adds workflow inputs for keystore material and implements input/secret/autogen priority logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +20 to +34
keystore_base64:
description: "Base64-encoded keystore (from SAVE-THESE-SECRETS.txt). Overrides ANDROID_KEYSTORE_BASE64 secret."
required: false
default: ""
type: string
key_alias:
description: "Signing key alias (from SAVE-THESE-SECRETS.txt). Overrides ANDROID_SIGNING_KEY_ALIAS secret."
required: false
default: ""
type: string
key_password:
description: "Signing key password (from SAVE-THESE-SECRETS.txt). Overrides ANDROID_SIGNING_KEY_PASSWORD secret."
required: false
default: ""
type: string

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

The workflow_dispatch inputs keystore_base64, key_alias, and key_password are not secret-protected by GitHub Actions (their values are stored in the workflow run metadata and may be visible to anyone with access to the run). Using them for an Android signing keystore/password risks leaking the private signing key. Consider removing these inputs and only supporting repository/environment secrets (or another secret-protected mechanism) for providing signing material.

Suggested change
keystore_base64:
description: "Base64-encoded keystore (from SAVE-THESE-SECRETS.txt). Overrides ANDROID_KEYSTORE_BASE64 secret."
required: false
default: ""
type: string
key_alias:
description: "Signing key alias (from SAVE-THESE-SECRETS.txt). Overrides ANDROID_SIGNING_KEY_ALIAS secret."
required: false
default: ""
type: string
key_password:
description: "Signing key password (from SAVE-THESE-SECRETS.txt). Overrides ANDROID_SIGNING_KEY_PASSWORD secret."
required: false
default: ""
type: string

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +117
EFFECTIVE_KS="${INPUT_KEYSTORE_BASE64:-$KEYSTORE_BASE64}"
EFFECTIVE_ALIAS="${INPUT_KEY_ALIAS:-$KEY_ALIAS_SECRET}"
EFFECTIVE_PASS="${INPUT_KEY_PASSWORD:-$KEY_PASS_SECRET}"
EFFECTIVE_STORE_PASS="${INPUT_KEY_PASSWORD:-${STORE_PASS_SECRET:-$EFFECTIVE_PASS}}"

# Mask passwords so they never appear in logs.
if [ -n "$EFFECTIVE_PASS" ]; then echo "::add-mask::$EFFECTIVE_PASS"; fi
if [ -n "$EFFECTIVE_STORE_PASS" ]; then echo "::add-mask::$EFFECTIVE_STORE_PASS"; fi

if [ -n "$EFFECTIVE_KS" ]; then
# ── User provided a keystore (via input or secret) ──────────────
echo "$EFFECTIVE_KS" | base64 --decode > "$KS_PATH"

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

When a user-provided keystore is used, the base64 keystore content itself is still highly sensitive (it contains the private key). Even if this step doesn’t currently print it, it’s safer to mask EFFECTIVE_KS/INPUT_KEYSTORE_BASE64 via ::add-mask:: to avoid accidental leakage via debugging or error output.

Copilot uses AI. Check for mistakes.
Comment on lines +115 to +122
if [ -n "$EFFECTIVE_KS" ]; then
# ── User provided a keystore (via input or secret) ──────────────
echo "$EFFECTIVE_KS" | base64 --decode > "$KS_PATH"
echo "has_keystore=true" >> "$GITHUB_OUTPUT"
echo "generated=false" >> "$GITHUB_OUTPUT"
echo "key_alias=$KEY_ALIAS_SECRET" >> "$GITHUB_OUTPUT"
echo "key_pass=$KEY_PASS_SECRET" >> "$GITHUB_OUTPUT"
echo "store_pass=$STORE_PASS_SECRET" >> "$GITHUB_OUTPUT"
echo "✅ Using saved keystore from repository secrets."
echo "key_alias=${EFFECTIVE_ALIAS:-osu-release}" >> "$GITHUB_OUTPUT"
echo "key_pass=${EFFECTIVE_PASS}" >> "$GITHUB_OUTPUT"
echo "store_pass=${EFFECTIVE_STORE_PASS}" >> "$GITHUB_OUTPUT"

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

If EFFECTIVE_KS is set but EFFECTIVE_PASS (and/or EFFECTIVE_ALIAS) is empty, the workflow will continue and dotnet publish will receive empty signing parameters, which will likely fail later with a less actionable error. Add an explicit validation/early-exit here to require the necessary password/alias fields whenever a keystore is provided.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants