forked from ppy/osu
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAndroidStartupFlags.cs
More file actions
128 lines (121 loc) · 5.29 KB
/
Copy pathAndroidStartupFlags.cs
File metadata and controls
128 lines (121 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.IO;
using Android.App;
using Debug = System.Diagnostics.Debug;
namespace osu.Android
{
/// <summary>
/// Tiny on-disk sentinel store that lets pre-<see cref="osu.Game.OsuGameBase"/> code
/// (e.g. <see cref="OsuGameActivity.OnCreate"/>) consult settings owned by
/// <see cref="osu.Game.Configuration.OsuConfigManager"/>.
///
/// <para>
/// The activity runs LONG before the config manager exists — Realm has to be
/// initialised first, and the activity is the place that needs to RUN safety
/// behaviours BEFORE Realm runs. The chicken-and-egg solution is a one-flag-
/// per-file sentinel pattern: when the user changes a startup-safety toggle
/// in-game, <see cref="OsuGameAndroid"/> writes (or deletes) a sentinel file
/// whose presence reflects the new value. The activity reads the sentinel
/// next launch.
/// </para>
///
/// <para>
/// Files live under <c>FilesDir</c> (internal app storage). Each flag is a
/// single empty file named <c>android_startup_disable_<name>.flag</c>.
/// Presence ⇒ "the user has explicitly disabled this safety net". Absence ⇒
/// "default behaviour" (per the matching OsuSetting default in
/// <see cref="osu.Game.Configuration.OsuConfigManager"/>).
/// </para>
///
/// <para>
/// All operations are best-effort and never throw out — diagnostics-grade
/// reliability semantics, like <see cref="CrashDiagnostics"/>.
/// </para>
/// </summary>
internal static class AndroidStartupFlags
{
public const string FLAG_CLEANUP_REALM_FIFOS_DISABLED = "android_startup_disable_realm_fifo_cleanup.flag";
public const string FLAG_DEFER_NATIVE_INIT_DISABLED = "android_startup_disable_defer_native_init.flag";
public const string FLAG_FRAME_SYNC_MIGRATION_ENABLED = "android_startup_enable_frame_sync_migration.flag";
/// <summary>
/// Verbose-logging opt-in sentinel. Presence ⇒ "user has enabled
/// verbose framework logging". Absence ⇒ "default, quiet logging
/// (Important+ only)". Quiet is the default because the framework's
/// runtime/input log is ~330+ KB per launch on Android (mostly
/// OpenTabletDriver detection + SDL platform chatter) and is not
/// useful in the steady state. Toggle from
/// Settings → Graphics → Android Performance.
/// </summary>
public const string FLAG_VERBOSE_LOGGING_ENABLED = "android_startup_enable_verbose_logging.flag";
/// <summary>
/// "Startup in progress" sentinel. Dropped near the very top of <see cref="OsuGameActivity.OnCreate"/>
/// and cleared a few seconds after <c>OsuGame.LoadComplete</c> by <see cref="OsuGameAndroid"/>.
/// If a fresh <c>OnCreate</c> finds this still present, the previous launch died (ANR / native
/// crash / OOM kill) before reaching the post-LoadComplete clear point, and we apply one-shot
/// safe-mode behaviours for THIS launch only.
/// </summary>
public const string FLAG_STARTUP_IN_PROGRESS = "android_startup_in_progress.flag";
private static string? resolveDir()
{
try
{
var ctx = Application.Context;
var files = ctx?.FilesDir;
if (files == null) return null;
string? path = files.AbsolutePath;
return string.IsNullOrEmpty(path) ? null : path;
}
catch (Exception e)
{
Debug.WriteLine($"[osu!] AndroidStartupFlags.resolveDir failed: {e.Message}");
return null;
}
}
/// <summary>
/// Returns true if a sentinel file with the given name exists in internal app storage.
/// </summary>
public static bool IsSet(string flagName)
{
try
{
string? dir = resolveDir();
if (dir == null) return false;
return File.Exists(Path.Combine(dir, flagName));
}
catch (Exception e)
{
Debug.WriteLine($"[osu!] AndroidStartupFlags.IsSet({flagName}) failed: {e.Message}");
return false;
}
}
/// <summary>
/// Create or remove the sentinel file according to <paramref name="set"/>.
/// Idempotent and never throws.
/// </summary>
public static void Set(string flagName, bool set)
{
try
{
string? dir = resolveDir();
if (dir == null) return;
string path = Path.Combine(dir, flagName);
if (set)
{
if (!File.Exists(path))
File.WriteAllText(path, string.Empty);
}
else
{
if (File.Exists(path))
File.Delete(path);
}
}
catch (Exception e)
{
Debug.WriteLine($"[osu!] AndroidStartupFlags.Set({flagName}, {set}) failed: {e.Message}");
}
}
}
}