Skip to content

Commit 01cb23d

Browse files
Skip redundant setRequestedOrientation calls to prevent ANR
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/b41f047d-4494-4c84-93a7-7854e96c9a67 Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
1 parent 5fceb84 commit 01cb23d

1 file changed

Lines changed: 42 additions & 14 deletions

File tree

osu.Android/OsuGameAndroid.cs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ public partial class OsuGameAndroid : OsuGame
8888
private object? activeMixersList;
8989

9090
private object? nativeBridges;
91+
92+
/// <summary>
93+
/// Last value passed to <see cref="OsuGameActivity.RequestedOrientation"/> by
94+
/// <see cref="updateOrientation"/>. Cached locally so we can short-circuit
95+
/// redundant updates without round-tripping through the activity getter, which
96+
/// itself performs a binder IPC on modern Android.
97+
/// </summary>
98+
private global::Android.Content.PM.ScreenOrientation? lastRequestedOrientation;
9199
private int currentRefreshRate;
92100

93101
public OsuGameAndroid(OsuGameActivity activity)
@@ -753,24 +761,44 @@ private void updateOrientation()
753761

754762
var orientation = MobileUtils.GetOrientation(this, currentScreen, gameActivity.IsTablet);
755763

764+
global::Android.Content.PM.ScreenOrientation desired;
765+
766+
switch (orientation)
767+
{
768+
case MobileUtils.Orientation.Locked:
769+
desired = global::Android.Content.PM.ScreenOrientation.Locked;
770+
break;
771+
772+
case MobileUtils.Orientation.Portrait:
773+
desired = global::Android.Content.PM.ScreenOrientation.Portrait;
774+
break;
775+
776+
case MobileUtils.Orientation.Default:
777+
desired = gameActivity.DefaultOrientation;
778+
break;
779+
780+
default:
781+
return;
782+
}
783+
784+
// Short-circuit when no change is required. We track the last requested orientation
785+
// locally because Activity.getRequestedOrientation() itself performs a binder IPC
786+
// on modern Android, and the whole point of this guard is to avoid binder traffic.
787+
// ScreenChanged fires on every screen push/pop and the resolved orientation rarely
788+
// differs between adjacent screens, so without this guard we flood the UI looper
789+
// with redundant Activity.setRequestedOrientation transactions, which under
790+
// system_server CPU pressure can wedge input dispatch and trigger an ANR
791+
// ("Input dispatching timed out ... Waited 10000ms for MotionEvent").
792+
if (lastRequestedOrientation == desired)
793+
return;
794+
795+
lastRequestedOrientation = desired;
796+
756797
gameActivity.RunOnUiThread(() =>
757798
{
758799
try
759800
{
760-
switch (orientation)
761-
{
762-
case MobileUtils.Orientation.Locked:
763-
gameActivity.RequestedOrientation = global::Android.Content.PM.ScreenOrientation.Locked;
764-
break;
765-
766-
case MobileUtils.Orientation.Portrait:
767-
gameActivity.RequestedOrientation = global::Android.Content.PM.ScreenOrientation.Portrait;
768-
break;
769-
770-
case MobileUtils.Orientation.Default:
771-
gameActivity.RequestedOrientation = gameActivity.DefaultOrientation;
772-
break;
773-
}
801+
gameActivity.RequestedOrientation = desired;
774802
}
775803
catch (Exception e)
776804
{

0 commit comments

Comments
 (0)