[Docs] (P13): the FCL silent death (status=34, SIGRTMIN+2) is recorded as an FCL-side debt with its soak evidence.

This commit is contained in:
2026-10-06 18:50:30 -04:00
parent 8bc39c79d2
commit ec7fc40ba5
9 changed files with 192 additions and 110 deletions
@@ -1,110 +0,0 @@
// MobileGL - MobileGL/MG_Test/Texture/VkClearManagerTest.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#include <gtest/gtest.h>
#include "Includes.h"
#include "Init.h"
#include <MG_Backend/DirectVulkan/Renderer/VkClearManager.h>
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
#include <MG_State/GLState/Core.h>
using namespace MobileGL;
using namespace MobileGL::MG_Backend::DirectVulkan;
class VkClearManagerTest : public ::testing::Test {
protected:
void SetUp() override { MobileGL::Initialize(); }
};
TEST_F(VkClearManagerTest, CollectGarbageRemovesExpiredTexturesAndTheirPendingClears) {
VkClearManager clearManager;
ASSERT_TRUE(clearManager.Initialize());
constexpr SizeT kTextureCount = 64;
Vector<GLuint> textureNames(kTextureCount, 0);
Vector<PendingClearKey> pendingKeys;
pendingKeys.reserve(kTextureCount);
const ClearAttachmentPayload clearPayload{
.mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
.color = FloatVec4(0.25f, 0.5f, 0.75f, 1.0f),
.depth = 0.5f,
};
for (SizeT i = 0; i < kTextureCount; ++i) {
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &textureNames[i]);
ASSERT_NE(textureNames[i], 0u);
{
const auto textureObject = MG_State::pGLContext->GetTextureObject(textureNames[i]);
ASSERT_NE(textureObject, nullptr);
const PendingClearKey key = VkClearManager::MakePendingClearKey(textureObject.get());
clearManager.QueueClear(clearPayload, textureObject);
EXPECT_TRUE(clearManager.HasPendingClear(key));
pendingKeys.emplace_back(key);
}
}
MG_Impl::GLImpl::DeleteTextures(static_cast<GLsizei>(textureNames.size()), textureNames.data());
for (Int i = 0; i < 255; ++i) {
EXPECT_EQ(clearManager.CollectGarbage(), 0u);
}
EXPECT_EQ(clearManager.CollectGarbage(), kTextureCount);
ClearAttachmentPayload outPayload{};
for (const auto& key : pendingKeys) {
EXPECT_FALSE(clearManager.HasPendingClear(key));
EXPECT_FALSE(clearManager.GetPendingClear(key, outPayload));
}
GLuint freshTexture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &freshTexture);
ASSERT_NE(freshTexture, 0u);
const auto freshTextureObject = MG_State::pGLContext->GetTextureObject(freshTexture);
ASSERT_NE(freshTextureObject, nullptr);
EXPECT_FALSE(clearManager.HasPendingClear(freshTextureObject.get()));
MG_Impl::GLImpl::DeleteTextures(1, &freshTexture);
clearManager.Shutdown();
}
TEST_F(VkClearManagerTest, StalePendingClearsAreRejectedBeforePeriodicGarbageCollection) {
VkClearManager clearManager;
ASSERT_TRUE(clearManager.Initialize());
GLuint texture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
ASSERT_NE(texture, 0u);
PendingClearKey key{};
{
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
ASSERT_NE(textureObject, nullptr);
key = VkClearManager::MakePendingClearKey(textureObject.get());
clearManager.QueueClear(ClearAttachmentPayload{
.mask = GL_COLOR_BUFFER_BIT,
.color = FloatVec4(1.0f, 0.25f, 0.5f, 0.75f),
}, textureObject);
EXPECT_TRUE(clearManager.HasPendingClear(key));
}
MG_Impl::GLImpl::DeleteTextures(1, &texture);
ClearAttachmentPayload outPayload{};
EXPECT_FALSE(clearManager.HasPendingClear(key));
EXPECT_FALSE(clearManager.GetPendingClear(key, outPayload));
EXPECT_FALSE(clearManager.HasPendingClear(key));
clearManager.Shutdown();
}
+1
View File
@@ -23,6 +23,7 @@
| P8 转出(B):`PipeCalls.def:260` `GenerateMipmap` 仍是 `kWaitApplied`,裁定 14 的理由(CPU 滤波碰 client 影子)已不成立,可改 `kWaitNone` | 性能工作(协议行为变更,需单独裁定) |
| P8 转出(C):server SSBO 标记过近似(窗口内每个绑定的 SSBO 都标);一个留在 SSBO 绑定上又当 restart EBO 用的 buffer 每次 draw 都回读 | 性能工作 |
| P13 转出(W5 翻转后,ID-P13-2 记录项,用户裁定记为债务):Magma monolith 走记录臂比前端臂慢约 16%——Y700 上 FCL MC 1.21.5、RD2 小场景、时钟未钉:记录臂 168 / 176 fps,同库强制前端臂 206 / 204 fps,即每帧 CPU 约 5.8 ms 对 4.9 ms(渲染线程都约占满一核);Espryt 持平(224 / 226 对 222)。疑因:`VulkanRenderer::SetupDraw` 在记录臂直接进 `SetupWireDraw`,绕过只在前端臂跑的 `TrySetupDrawFastPath`(PLAN-P13 §1.3 已提示「换臂前先量」)。W6 删前端臂后这部分成本固定下来 | P13 收官后:设备上钉时钟 profile Magma monolith 每 draw 成本(simpleperf,对比 W5 前端臂数据),再决定给 wire draw 臂补快路径;P13 内不优化 |
| P13 转出(FCL 浸泡,用户裁定:FCL 暂不改、MobileGL 不做规避):FCL game process can die silently (exit SIGNALED status=34, SIGRTMIN+2): the JVM signal reset after renderer selection drops libcore's AsynchronousCloseMonitor handler, and FCL's okhttp/Okio watchdog then kills the process; renderer-independent (reproduced on P12 and P13 libraries, both backends; untested with other renderers)。浸泡:P13 库 30 次(Magma 22 / Espryt 8)死 18 次、P12 库 10 次死 2 次,全部 status=34,无 tombstone、无 kgsl;证据与机理见 [`p13/fcl-soak/README.md`](p13/fcl-soak/README.md) | fix belongs in FCL (save/restore libcore's SIGRTMIN+2 sigaction around JVM creation); left for the user |
| P8 转出(monolith,ID-P8-13):9 条 monolith 缺陷真实内容 0 命中,不在 dev 上修——Espryt `*IndirectCount` / 原生 indirect `gl_BaseVertex` / fp64 收窄读未同步影子;Magma `glMultiDrawArraysIndirectCount` CPU 臂同病;Magma 录制中途 `SyncGpuWrites` → SIGSEGV;Espryt RGB16F / RGB32F CPU 滤波读陈旧影子、R11F / 深度链无视 BASE / MAX;Magma 无 BLIT 颜色格式缺着色器 mip 臂;Espryt 拷贝后 `glGetTexImage` 读拷贝前影子(证据见 `notes/p8/{B,C,D,E}.md`) | P13(monolith 换到已修好的记录臂) |
| P8 转出(monolith,feat,ID-P8-14):feat 的 monolith 臂每次 indirect draw 在命令缓冲有 GPU 写时整 buffer 同步回读(`SyncClientSideVertexArraysForIndirectFetch`,`62bfe461`,dev 无);Magma 的 split 构建 monolith 深度 mip 不传 view 类型,无深度 `BLIT_DST` 的设备上 1D 深度链会拿到 2D view(推断,Release 下断言编译掉,SV) | P13(monolith 换臂) |
| P8 转出(MD):dev 的 `RingAllocateSlow` 在出错的上下文上无上限地排水(设备上挂在 `glFinish`) | 小修(dev) |
@@ -0,0 +1,55 @@
# FCL silent-death soak (P13, 2026-10-07)
User request: soak FCL launches on the Y700 (Magma, Espryt control) to root-cause the "silent
Magma death after MobileGL init" seen once in the P13 FCL smoke. User decision afterwards: the
cause is FCL's, leave FCL as-is, no MobileGL workaround; recorded as a debt
(`../../DEBTS.md`, "FCL game process can die silently").
## Result
Every silent death is `ApplicationExitInfo reason=2 (SIGNALED) status=34` - signal 34 is
`SIGRTMIN+2`, the wake-up signal of Android libcore's `AsynchronousCloseMonitor`. No tombstone,
no kgsl/GPU fault line, no debuggerd output, in any death.
Mechanism (ftrace `signal_generate` / `signal_deliver` filtered on `sig==34`, plus a 0.5 s
sampler of `/proc/<pid>/status` `SigCgt`):
1. FCL's game process starts with Android's handler set (`SigCgt 0x6e400084f8`, bit 33 = sig 34
caught).
2. About 0.5 s after FCL logs `Renderer: MobileGLDev...` (JVM start for the game), the whole set
is replaced by the JVM's (`SigCgt 0x1005cef`, later `0x2000000001005cef`): sig 34 is no longer
caught.
3. FCL's own okhttp stack (`Okio Watchdog` thread) times out a blocked read and sends sig 34 to the
reading `onPool-worker-N` thread (`AsynchronousCloseMonitor::signalBlockedThreads`, `code=-6`
= `SI_TKILL`).
4. With the default disposition the kernel takes the fatal fast path: `signal_generate` with no
`signal_deliver`, and the whole process dies. In the relaunched launcher process the same
watchdog's signals are delivered to libcore's handler (`sa_handler=79a72f3fa0`) and nothing
happens.
Renderer-independent: reproduced with the P13 library on both backends and with the pre-P13 (P12
end, `743f4e8e`) library; several deaths happen before MobileGL has logged anything beyond FCL's
renderer line. Rate depends on whether FCL's background network read times out in that window
(network-dependent), not on the GL library. Untested with non-MobileGL renderers.
Fix belongs in FCL: save libcore's `SIGRTMIN+2` sigaction before creating the JVM and restore it
after (or do not reset that signal). Left for the user.
## Soak sizes
| soak | library | runs | deaths (all status=34) |
|---|---|---|---|
| clean (`soak-p13-clean-summary.txt`, `soak2.sh` with the SigCgt sampler and per-run ftrace) | P13 FCL lib at `c1e985c8` | 30 (22 Magma, 8 Espryt) | 18: Magma 13/22, Espryt 5/8 |
| P12 control (`soak-p12-control-summary.txt`) | P12 end `743f4e8e` | 10 Magma | 2 |
Earlier P13 runs (first 5-run soak) are not counted: two soak scripts were found driving the
phone at once and force-stopping each other's runs; `soak2.sh` now takes a lock.
Per-death evidence kept here for one representative death (clean run 4, Magma): the ftrace
excerpt (`run004-magma-ftrace-signal34.txt` - pid 27854 is the dying process's worker, generated
with no delivery), the SigCgt transitions (`run004-magma-sigcgt-transitions.txt`) and the logcat
lines (`run004-magma-logcat-excerpt.txt`). The full per-run logcat/dmesg/ftrace/exit-info
captures stayed in the session scratchpad and were not committed.
Device restored afterwards: original FCL `libMobileGL.so` (md5 checked) and `config.json`, ftrace
signal events and `tracing_on` off, `svc power stayon false`, anland relaunched.
@@ -0,0 +1,5 @@
Okio Watchdog-28064 [002] dN.1. 283577.703953: signal_generate: sig=34 errno=0 code=-6 comm=onPool-worker-2 pid=27854 grp=0 res=0
Okio Watchdog-28615 [007] d..1. 283595.889904: signal_generate: sig=34 errno=0 code=-6 comm=onPool-worker-4 pid=28598 grp=0 res=0
onPool-worker-4-28598 [002] d..1. 283595.890140: signal_deliver: sig=34 errno=0 code=-6 sa_handler=79a72f3fa0 sa_flags=0
Okio Watchdog-28615 [003] d..1. 283595.891463: signal_generate: sig=34 errno=0 code=-6 comm=onPool-worker-5 pid=28599 grp=0 res=0
onPool-worker-5-28599 [004] d..1. 283595.891590: signal_deliver: sig=34 errno=0 code=-6 sa_handler=79a72f3fa0 sa_flags=0
@@ -0,0 +1,7 @@
10-07 05:16:16.527 27780 28482 D FCL Debug: Renderer: MobileGLDevMagma
10-07 05:16:17.879 2564 2870 I ActivityManager: Process com.tungsten.fcl.mgdebug.debug (pid 27780) has died: fg TOP
10-07 05:16:17.887 1375 1375 I Zygote : Process 27780 exited due to signal 34 (Unknown signal 34)
10-07 05:16:36.030 28561 28598 W FCL : at com.android.okhttp.okio.Okio$3.newTimeoutException(Okio.java:214)
10-07 05:16:36.030 28561 28598 W FCL : at com.android.okhttp.okio.Okio$2.read(Okio.java:138)
10-07 05:16:36.030 28561 28599 W FCL : at com.android.okhttp.okio.Okio$3.newTimeoutException(Okio.java:214)
10-07 05:16:36.030 28561 28599 W FCL : at com.android.okhttp.okio.Okio$2.read(Okio.java:138)
@@ -0,0 +1,4 @@
05:16:00.611 27304 0000006e400084f8
05:16:07.721 27780 0000006e400084f8
05:16:17.036 27780 0000000001005cef
05:16:18.125 28561 0000006e400084f8
@@ -0,0 +1,12 @@
# run backend result mglLines dataArm lastMGL deathTime exitInfo tombstones kgsl
1 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=04:33:09.184 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=478MB description=stop com.tu] tomb+=0 kgsl=0
2 magma DIED mgl=283 arm=? inworldMarks=0 lastMGL=04:36:29.619 death=04:36:31.300 exit=[ process=com.tungsten.fcl.mgdebug.debug reason=2 (SIGNALED) subreason=0 (UNKNOWN) status=34; importance=100 pss=0.00 rss=0.00 description=null state=empty trace] tomb+=0 kgsl=0
3 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=04:39:48.473 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=0.00 description=stop com.tun] tomb+=0 kgsl=0
4 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=04:43:07.002 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=522MB description=stop com.tu] tomb+=0 kgsl=0
5 magma DIED mgl=281 arm=? inworldMarks=0 lastMGL=04:46:26.459 death=04:46:28.258 exit=[ process=com.tungsten.fcl.mgdebug.debug reason=2 (SIGNALED) subreason=0 (UNKNOWN) status=34; importance=100 pss=0.00 rss=470MB description=null state=empty trac] tomb+=0 kgsl=0
6 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=04:49:46.430 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=585MB description=stop com.tu] tomb+=0 kgsl=0
7 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=04:53:05.341 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=0.00 description=stop com.tun] tomb+=0 kgsl=0
8 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=04:56:24.260 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=0.00 description=stop com.tun] tomb+=0 kgsl=0
9 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=04:59:44.714 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=0.00 description=stop com.tun] tomb+=0 kgsl=0
10 magma ok mgl=281 arm=? inworldMarks=9 lastMGL=05:03:05.439 death= exit=[ process=com.tungsten.fcl.mgdebug.debug reason=10 (USER REQUESTED) subreason=21 (FORCE STOP) status=0; importance=100 pss=0.00 rss=0.00 description=stop com.tun] tomb+=0 kgsl=0
soak done
@@ -0,0 +1,32 @@
# run backend result mgl arm inworld deathTime exit sig34CaughtAtLaunch sig34CaughtInGame firstUncaught firstMGL ftraceFatal34 tomb+ kgsl
1 magma ok mgl=286 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=05:06:18.093 firstMGL=05:06:17.756 sig34gen/deliv=0/0 tomb+=0 kgsl=0
2 espryt DIED mgl=1 arm=? inworld=0 death=05:09:39.234 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:09:38.336 firstMGL=05:09:37.876 sig34gen/deliv=3/2 tomb+=0 kgsl=0
3 espryt ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=05:12:57.977 firstMGL=05:12:57.414 sig34gen/deliv=0/0 tomb+=0 kgsl=0
4 magma DIED mgl=1 arm=? inworld=0 death=05:16:17.879 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:16:17.036 firstMGL=05:16:16.527 sig34gen/deliv=3/2 tomb+=0 kgsl=0
5 magma ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=05:19:38.520 firstMGL=05:19:37.984 sig34gen/deliv=0/0 tomb+=0 kgsl=0
6 magma DIED mgl=285 arm=record inworld=0 death=05:23:11.237 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:23:02.344 firstMGL=05:23:01.798 sig34gen/deliv=3/2 tomb+=0 kgsl=0
7 magma DIED mgl=307 arm=record inworld=0 death=05:26:31.587 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:26:22.419 firstMGL=05:26:22.161 sig34gen/deliv=2/1 tomb+=0 kgsl=0
8 espryt ok mgl=286 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=05:29:41.760 firstMGL=05:29:41.171 sig34gen/deliv=0/0 tomb+=0 kgsl=0
9 magma DIED mgl=285 arm=record inworld=0 death=05:33:10.889 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:33:02.016 firstMGL=05:33:01.462 sig34gen/deliv=3/2 tomb+=0 kgsl=0
10 magma DIED mgl=307 arm=record inworld=9 death=05:36:40.562 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:36:23.625 firstMGL=05:36:23.163 sig34gen/deliv=3/2 tomb+=0 kgsl=0
11 magma DIED mgl=285 arm=record inworld=0 death=05:39:51.877 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:39:42.608 firstMGL=05:39:42.458 sig34gen/deliv=1/0 tomb+=0 kgsl=0
12 magma ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=05:43:02.482 firstMGL=05:43:02.171 sig34gen/deliv=0/0 tomb+=0 kgsl=0
13 magma ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=05:46:26.224 firstMGL=05:46:25.920 sig34gen/deliv=0/0 tomb+=0 kgsl=0
14 espryt DIED mgl=307 arm=record inworld=0 death=05:49:55.699 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:49:46.577 firstMGL=05:49:46.268 sig34gen/deliv=2/1 tomb+=0 kgsl=0
15 espryt DIED mgl=307 arm=record inworld=0 death=05:53:15.311 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:53:06.094 firstMGL=05:53:05.875 sig34gen/deliv=3/2 tomb+=0 kgsl=0
16 magma ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=05:56:28.893 firstMGL=05:56:28.643 sig34gen/deliv=0/0 tomb+=0 kgsl=0
17 magma DIED mgl=307 arm=record inworld=0 death=05:59:59.806 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=05:59:50.546 firstMGL=05:59:50.377 sig34gen/deliv=3/2 tomb+=0 kgsl=0
18 magma DIED mgl=307 arm=record inworld=0 death=06:03:19.582 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:03:10.723 firstMGL=06:03:10.149 sig34gen/deliv=2/1 tomb+=0 kgsl=0
19 espryt DIED mgl=1 arm=? inworld=0 death=06:06:32.113 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:06:30.959 firstMGL=06:06:30.748 sig34gen/deliv=3/2 tomb+=0 kgsl=0
20 magma ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=06:09:54.474 firstMGL=06:09:54.306 sig34gen/deliv=0/0 tomb+=0 kgsl=0
21 magma DIED mgl=1 arm=? inworld=0 death=06:13:19.683 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:13:18.626 firstMGL=06:13:18.317 sig34gen/deliv=3/2 tomb+=0 kgsl=0
22 magma ok mgl=286 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=06:16:38.187 firstMGL=06:16:37.905 sig34gen/deliv=0/0 tomb+=0 kgsl=0
23 espryt ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=06:19:59.006 firstMGL=06:19:58.639 sig34gen/deliv=0/0 tomb+=0 kgsl=0
24 magma DIED mgl=1 arm=? inworld=0 death=06:23:18.419 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:23:17.719 firstMGL=06:23:17.057 sig34gen/deliv=3/2 tomb+=0 kgsl=0
25 magma DIED mgl=307 arm=record inworld=0 death=06:26:49.118 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:26:39.978 firstMGL=06:26:39.668 sig34gen/deliv=2/1 tomb+=0 kgsl=0
26 espryt DIED mgl=286 arm=record inworld=9 death=06:30:16.358 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:29:59.442 firstMGL=06:29:58.964 sig34gen/deliv=3/2 tomb+=0 kgsl=0
27 magma ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=06:33:20.624 firstMGL=06:33:19.958 sig34gen/deliv=0/0 tomb+=0 kgsl=0
28 espryt ok mgl=307 arm=record inworld=9 death=- exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=no firstUncaught=06:36:41.240 firstMGL=06:36:41.049 sig34gen/deliv=0/0 tomb+=0 kgsl=0
29 magma DIED mgl=307 arm=record inworld=0 death=06:40:13.295 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:40:03.995 firstMGL=06:40:03.840 sig34gen/deliv=3/2 tomb+=0 kgsl=0
30 magma DIED mgl=1 arm=? inworld=0 death=06:43:25.315 exit=[reason=2 (SIGNALED) reason=0 (UNKNOWN) status=34 ] launch34=yes game34=yes firstUncaught=06:43:24.417 firstMGL=06:43:23.951 sig34gen/deliv=3/2 tomb+=0 kgsl=0
31 magma DIED mgl=1272 arm=? inworld=0 death=06:46:49.476 exit=[reason=10 (USER REQUESTED) reason=21 (FORCE STOP) status=0 ] launch34=yes game34=yes firstUncaught=06:46:48.711 firstMGL=06:46:48.124 sig34gen/deliv=0/0 tomb+=0 kgsl=0
@@ -0,0 +1,76 @@
#!/bin/bash
# soak2.sh <runs-magma> <runs-espryt> <secs-in-world>: FCL launch soak (ONE instance at a time - it takes a
# lock) with diagnostics, plus a device-side sampler of the FCL process's caught-signal mask (SigCgt), so a
# death by signal 34 can be tied to whether bionic/libcore's SIGRTMIN+2 handler is still installed.
export MSYS_NO_PATHCONV=1
NM=${1:-30}; NE=${2:-10}; SECS=${3:-150}
BASE=${SOAK_DIR:?set SOAK_DIR}
LOCK=/c/Users/yello/AppData/Local/Temp/claude/C--Users-yello-AndroidStudioProjects-FoldCraftLauncher-MobileGL/0e0e570f-5721-41d8-9d0f-80fcde638a84/scratchpad/soak.lock
if ! mkdir "$LOCK" 2>/dev/null; then echo "another soak holds $LOCK"; exit 1; fi
trap 'rmdir "$LOCK"' EXIT
mkdir -p "$BASE"
PKG=com.tungsten.fcl.mgdebug.debug
CFG=/data/data/$PKG/files/config.json
SUM=$BASE/summary.txt
echo "# run backend result mgl arm inworld deathTime exit sig34CaughtAtLaunch sig34CaughtInGame firstUncaught firstMGL ftraceFatal34 tomb+ kgsl" >> "$SUM"
adb logcat -G 16M >/dev/null 2>&1
# The sampler: every 0.5 s, "<time> <pid> <SigCgt>" for the package's main process.
adb shell "su -c 'cat > /data/local/tmp/p13/sigsample.sh'" <<'EOS'
end=$(( $(date +%s) + $1 ))
while [ $(date +%s) -lt $end ]; do
p=$(pidof com.tungsten.fcl.mgdebug.debug | cut -d" " -f1)
if [ -n "$p" ]; then echo "$(date +%H:%M:%S.%N | cut -c1-12) $p $(grep SigCgt /proc/$p/status | cut -f2)"; fi
sleep 0.5
done
EOS
plan=""
for i in $(seq 1 $NM); do plan="$plan magma"; done
for i in $(seq 1 $NE); do plan="$plan espryt"; done
order=$(echo $plan | tr ' ' '\n' | awk 'BEGIN{srand(29)} {print rand()"\t"$0}' | sort | cut -f2)
idx=0
for be in $order; do
idx=$((idx+1))
lvl=$(adb shell dumpsys battery | grep level | tr -dc 0-9)
if [ "${lvl:-100}" -lt 40 ]; then echo "battery $lvl - stopping" >> "$SUM"; break; fi
OUT=$BASE/run$(printf %03d $idx)-$be; mkdir -p "$OUT"
case $be in espryt) C=cfg-espryt.json;; *) C=cfg-magma.json;; esac
adb shell "su -c 'am force-stop $PKG; cat /data/local/tmp/p13/$C > $CFG'"
adb shell "su -c 'ls /data/tombstones | wc -l'" > "$OUT/tomb-before.txt"
adb shell "su -c 'dmesg -c >/dev/null 2>&1; echo > /sys/kernel/tracing/trace'"
adb logcat -b all -c
adb shell "svc power stayon true; wm dismiss-keyguard" >/dev/null 2>&1
adb shell "su -c 'sh /data/local/tmp/p13/sigsample.sh $((SECS + 40))'" > "$OUT/sigcgt.txt" 2>&1 &
SAMP=$!
sleep 1
adb shell monkey -p $PKG -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1
sleep $((SECS + 45))
wait $SAMP 2>/dev/null
adb exec-out screencap -p > "$OUT/screen.png"
adb logcat -b all -d > "$OUT/logcat.txt"
adb shell "su -c 'dmesg'" > "$OUT/dmesg.txt" 2>/dev/null
adb shell "su -c 'cat /sys/kernel/tracing/trace'" > "$OUT/ftrace.txt" 2>/dev/null
adb shell "dumpsys activity exit-info $PKG" > "$OUT/exitinfo.txt" 2>/dev/null
adb shell "su -c 'ls /data/tombstones | wc -l'" > "$OUT/tomb-after.txt"
adb shell "su -c 'am force-stop $PKG'"
died=$(grep -ac "Process $PKG (pid [0-9]*) has died" "$OUT/logcat.txt")
mgl=$(grep -ac " MobileGL" "$OUT/logcat.txt")
arm=$(grep -ao "monolith data arm = [a-z]*" "$OUT/logcat.txt" | head -1 | awk '{print $NF}')
inworld=$(grep -ac "Server thread\|Preparing spawn area\|Loaded [0-9]* advancements\|joined the game" "$OUT/logcat.txt")
firstmgl=$(grep -a " MobileGL" "$OUT/logcat.txt" | head -1 | cut -c7-18)
deatht=$(grep -a "Process $PKG (pid [0-9]*) has died" "$OUT/logcat.txt" | head -1 | cut -c7-18)
ex=$(grep -aE "reason=" "$OUT/exitinfo.txt" | head -1 | grep -oE "reason=[0-9]+ \([A-Z_ ]+\)|status=[0-9]+" | tr '\n' ' ')
# SigCgt bit 33 = signal 34 (SIGRTMIN+2, libcore's async-close wakeup).
bit() { [ -z "$1" ] && { echo "?"; return; }; [ $(( (0x$1 >> 33) & 1 )) -eq 1 ] && echo yes || echo no; }
launchMask=$(grep -aE "^[0-9:.]+ [0-9]+ [0-9a-f]{16}" "$OUT/sigcgt.txt" | head -1 | awk '{print $3}')
gameMask=$(grep -aE "^[0-9:.]+ [0-9]+ [0-9a-f]{16}" "$OUT/sigcgt.txt" | sed -n 60p | awk '{print $3}')
firstUn=$(grep -aE "^[0-9:.]+ [0-9]+ [0-9a-f]{16}" "$OUT/sigcgt.txt" | while read t p m; do [ "$(bit $m)" = no ] && { echo $t; break; }; done)
# A sig 34 generated toward the package with no matching delivery = the kernel's fatal fast path.
gen=$(grep -ac "signal_generate: sig=34" "$OUT/ftrace.txt"); del=$(grep -ac "signal_deliver: sig=34" "$OUT/ftrace.txt")
tb=$(( $(tr -dc 0-9 < "$OUT/tomb-after.txt") - $(tr -dc 0-9 < "$OUT/tomb-before.txt") ))
kg=$(grep -aciE "kgsl.*(fault|hang|recover|snapshot)|adreno.*fault" "$OUT/dmesg.txt")
res=ok; [ "$died" -gt 0 ] && res=DIED
echo "$idx $be $res mgl=$mgl arm=${arm:-?} inworld=$inworld death=${deatht:--} exit=[$ex] launch34=$(bit "$launchMask") game34=$(bit "$gameMask") firstUncaught=${firstUn:--} firstMGL=${firstmgl:--} sig34gen/deliv=$gen/$del tomb+=$tb kgsl=$kg" >> "$SUM"
if [ "$res" = ok ] && [ $((idx % 5)) -ne 0 ]; then rm -f "$OUT/logcat.txt" "$OUT/dmesg.txt" "$OUT/ftrace.txt"; fi
done
adb shell "svc power stayon false"
echo "soak done" >> "$SUM"