fix(runtime): keep Xray's startup output so a failed core can be diagnosed
The monitor thread read the core's merged stdout/stderr and dropped
every line:
process.inputStream.bufferedReader().use { reader ->
reader.forEachLine { _ -> }
}
so the only trace of a core that died at startup was "Xray process
exited with code 23", with nothing to say why. That exit is real and
intermittent - it showed up on both a handset and an emulator - and
was undiagnosable in the field.
Keep at most 40 lines, and only from the core's first 10 seconds, then
log them when the exit code is non-zero. A core up longer than that may
be carrying traffic and its log can name destinations, which must never
reach the device log (rule 95), so past the window the buffer is
dropped rather than kept.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
4e5c7a02db
commit
e7ef251882
1 file changed
+25
-1
+25
-1
@@ -39,6 +39,13 @@ object XrayCoreManager {
|
|||||||
|
|
||||||
private const val NOTIFICATION_ID = 1
|
private const val NOTIFICATION_ID = 1
|
||||||
private const val TAG = "XrayCoreManager"
|
private const val TAG = "XrayCoreManager"
|
||||||
|
|
||||||
|
// The core's output is kept only for its first seconds, and only to explain
|
||||||
|
// a non-zero exit. A core that has been up longer than this may be carrying
|
||||||
|
// traffic, and its log can name destinations, which must never reach the
|
||||||
|
// device log (rule 95) - so past the window the buffer is dropped.
|
||||||
|
private const val STARTUP_LOG_WINDOW_MS = 10_000L
|
||||||
|
private const val STARTUP_LOG_MAX_LINES = 40
|
||||||
private var xrayProcess: Process? = null
|
private var xrayProcess: Process? = null
|
||||||
private var countDownTimer: CountDownTimer? = null
|
private var countDownTimer: CountDownTimer? = null
|
||||||
private var seconds = 0
|
private var seconds = 0
|
||||||
@@ -349,12 +356,29 @@ object XrayCoreManager {
|
|||||||
// Monitor process in a separate thread to detect crash
|
// Monitor process in a separate thread to detect crash
|
||||||
Thread {
|
Thread {
|
||||||
try {
|
try {
|
||||||
|
val startedAt = System.currentTimeMillis()
|
||||||
|
val startupLog = ArrayDeque<String>()
|
||||||
process.inputStream.bufferedReader().use { reader ->
|
process.inputStream.bufferedReader().use { reader ->
|
||||||
reader.forEachLine { _ -> }
|
reader.forEachLine { line ->
|
||||||
|
if (System.currentTimeMillis() - startedAt <= STARTUP_LOG_WINDOW_MS) {
|
||||||
|
if (startupLog.size >= STARTUP_LOG_MAX_LINES) startupLog.removeFirst()
|
||||||
|
startupLog.addLast(line)
|
||||||
|
} else if (startupLog.isNotEmpty()) {
|
||||||
|
startupLog.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val exitCode = process.waitFor()
|
val exitCode = process.waitFor()
|
||||||
|
if (exitCode != 0 && startupLog.isNotEmpty()) {
|
||||||
|
Log.e(
|
||||||
|
TAG,
|
||||||
|
"Xray process exited with code $exitCode; startup output:\n" +
|
||||||
|
startupLog.joinToString("\n")
|
||||||
|
)
|
||||||
|
} else {
|
||||||
Log.e(TAG, "Xray process exited with code $exitCode")
|
Log.e(TAG, "Xray process exited with code $exitCode")
|
||||||
|
}
|
||||||
if (xrayProcess === process &&
|
if (xrayProcess === process &&
|
||||||
AppConfigs.V2RAY_CONFIG?.RUNTIME_TOKEN == config.RUNTIME_TOKEN &&
|
AppConfigs.V2RAY_CONFIG?.RUNTIME_TOKEN == config.RUNTIME_TOKEN &&
|
||||||
(AppConfigs.V2RAY_STATE == AppConfigs.V2RAY_STATES.V2RAY_CONNECTED ||
|
(AppConfigs.V2RAY_STATE == AppConfigs.V2RAY_STATES.V2RAY_CONNECTED ||
|
||||||
|
|||||||
Reference in new issue
Block a user