Skip to content

Commit 34ff418

Browse files
Copilotwinnerspiros
andcommitted
Fix Android build: add file locking to ELF patcher + restore XA0141 suppression as fallback
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/d87f8128-0f76-4738-a1c6-f3f37e742734 Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
1 parent d32427e commit 34ff418

2 files changed

Lines changed: 77 additions & 8 deletions

File tree

build/PatchElfPageSize.targets

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,77 @@ for (int i = 0; i < e_shnum; i++)
169169
WU64(newData, newSh + 24, translate(RU64(data, oldSh + 24))); // sh_offset
170170
}
171171
172-
// ── Write patched file ──────────────────────────────────────────────
173-
System.IO.File.WriteAllBytes(FilePath, newData);
174-
WasPatched = true;
175-
Log.LogMessage(MessageImportance.High,
176-
"PatchElfPageSize: patched {0} (align 0x1000 -> 0x{1:X}, +{2} bytes)",
177-
System.IO.Path.GetFileName(FilePath), pageSize, newData.Length - data.Length);
172+
// ── Write patched file (with lock to handle parallel builds) ────────
173+
string lockFile = FilePath + ".patch-lock";
174+
System.IO.FileStream lockStream = null;
175+
try
176+
{
177+
// Acquire an exclusive lock file to prevent concurrent writes.
178+
// Retry up to 30 times with 1-second delays (handles parallel MSBuild nodes).
179+
for (int attempt = 0; attempt < 30; attempt++)
180+
{
181+
try
182+
{
183+
lockStream = new System.IO.FileStream(lockFile,
184+
System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite,
185+
System.IO.FileShare.None);
186+
break;
187+
}
188+
catch (System.IO.IOException)
189+
{
190+
System.Threading.Thread.Sleep(1000);
191+
}
192+
}
193+
194+
if (lockStream == null)
195+
{
196+
Log.LogMessage(MessageImportance.High,
197+
"PatchElfPageSize: could not acquire lock for {0}, skipping (another build node may be patching it)",
198+
System.IO.Path.GetFileName(FilePath));
199+
return true;
200+
}
201+
202+
// Re-read and re-check: another node may have already patched while we waited.
203+
byte[] freshData = System.IO.File.ReadAllBytes(FilePath);
204+
bool stillNeeds = false;
205+
if (freshData.Length >= 64 && freshData[0] == 0x7F && freshData[4] == 2 && freshData[5] == 1)
206+
{
207+
ulong freshPhoff = RU64(freshData, 32);
208+
int freshPhentsz = (int)(freshData[54] | (freshData[55] << 8));
209+
int freshPhnum = (int)(freshData[56] | (freshData[57] << 8));
210+
for (int i = 0; i < freshPhnum; i++)
211+
{
212+
int h = (int)freshPhoff + i * freshPhentsz;
213+
if (RU32(freshData, h) == PT_LOAD && RU64(freshData, h + 48) < (ulong)pageSize)
214+
{
215+
stillNeeds = true;
216+
break;
217+
}
218+
}
219+
}
220+
221+
if (!stillNeeds)
222+
{
223+
Log.LogMessage(MessageImportance.Low,
224+
"PatchElfPageSize: {0} was already patched by another build node",
225+
System.IO.Path.GetFileName(FilePath));
226+
return true;
227+
}
228+
229+
System.IO.File.WriteAllBytes(FilePath, newData);
230+
WasPatched = true;
231+
Log.LogMessage(MessageImportance.High,
232+
"PatchElfPageSize: patched {0} (align 0x1000 -> 0x{1:X}, +{2} bytes)",
233+
System.IO.Path.GetFileName(FilePath), pageSize, newData.Length - data.Length);
234+
}
235+
finally
236+
{
237+
if (lockStream != null)
238+
{
239+
lockStream.Dispose();
240+
try { System.IO.File.Delete(lockFile); } catch { }
241+
}
242+
}
178243
]]></Code>
179244
</Task>
180245
</UsingTask>

osu.Android.props

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
<!-- NullabilityInfoContextSupport is disabled by default for Android -->
99
<NullabilityInfoContextSupport>true</NullabilityInfoContextSupport>
1010
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
11+
<!-- Suppress XA0141 page-size warnings during build. The actual .so files are patched
12+
to 16 KB alignment by build/PatchElfPageSize.targets, but the SDK check runs before
13+
the patch in some build orderings. This suppression is harmless since we do fix them. -->
14+
<AndroidPageSize16KBCompatibilityCheck>false</AndroidPageSize16KBCompatibilityCheck>
1115
</PropertyGroup>
12-
<!-- Patch NuGet-provided .so files that ship with 4 KB ELF alignment to 16 KB
13-
before the Android SDK validates page sizes. See build/PatchElfPageSize.targets.
16+
<!-- Patch NuGet-provided .so files that ship with 4 KB ELF alignment to 16 KB.
17+
See build/PatchElfPageSize.targets for details.
1418
TODO: Remove once ppy.Veldrid.SPIRV ships 16 KB-aligned native libraries. -->
1519
<Import Project="$(MSBuildThisFileDirectory)build\PatchElfPageSize.targets" />
1620
<!-- Release-only optimisations: AOT for low-latency gameplay, trimming for smaller APK.

0 commit comments

Comments
 (0)