From 60accbe1d1b1e1fbe9b1bb0f4701bdcc12a98589 Mon Sep 17 00:00:00 2001 From: CelloSerenity <195480169+CelloSerenity@users.noreply.github.com> Date: Sun, 26 Jul 2026 11:38:58 -0600 Subject: [PATCH] Reuse open remote server for JIT bounce-back to avoid cold-launch race --- StikDebug/Device/JITEnableContext.swift | 39 +++++++++++++++++-------- StikDebug/JSSupport/RunJSView.swift | 7 ++++- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/StikDebug/Device/JITEnableContext.swift b/StikDebug/Device/JITEnableContext.swift index bb2d670..ff6e7cc 100644 --- a/StikDebug/Device/JITEnableContext.swift +++ b/StikDebug/Device/JITEnableContext.swift @@ -645,18 +645,7 @@ final class JITEnableContext { func relaunchApp(_ bundleID: String, logger: LogFunc? = nil) -> Bool { do { let pid = try withConnectedRemoteServer { remoteServer in - try withProcessControl(remoteServer: remoteServer) { processControl in - var pid: UInt64 = 0 - let ffiError = bundleID.withCString { bundleID in - process_control_launch_app(processControl, bundleID, nil, 0, nil, 0, false, false, &pid) - } - - if let ffiError { - throw error(from: ffiError, fallback: "Failed to return to app") - } - - return pid - } + try relaunchApp(bundleID, remoteServer: remoteServer) } emitLog("Returned to \(bundleID) (PID \(pid))", logger: logger) @@ -667,6 +656,32 @@ final class JITEnableContext { } } + func relaunchApp(_ bundleID: String, usingRemoteServer remoteServer: OpaquePointer, logger: LogFunc? = nil) -> Bool { + do { + let pid = try relaunchApp(bundleID, remoteServer: remoteServer) + emitLog("Returned to \(bundleID) (PID \(pid))", logger: logger) + return true + } catch { + emitLog("Failed to return to \(bundleID): \(error.localizedDescription)", logger: logger) + return false + } + } + + private func relaunchApp(_ bundleID: String, remoteServer: OpaquePointer) throws -> UInt64 { + try withProcessControl(remoteServer: remoteServer) { processControl in + var pid: UInt64 = 0 + let ffiError = bundleID.withCString { bundleID in + process_control_launch_app(processControl, bundleID, nil, 0, nil, 0, false, false, &pid) + } + + if let ffiError { + throw error(from: ffiError, fallback: "Failed to return to app") + } + + return pid + } + } + func startSyslogRelay(handler: @escaping SyslogLineHandler, onError: @escaping SyslogErrorHandler) { do { try ensureTunnel() diff --git a/StikDebug/JSSupport/RunJSView.swift b/StikDebug/JSSupport/RunJSView.swift index 674bc32..42c85ba 100644 --- a/StikDebug/JSSupport/RunJSView.swift +++ b/StikDebug/JSSupport/RunJSView.swift @@ -132,7 +132,12 @@ final class RunJSViewModel: ObservableObject, Identifiable, @unchecked Sendable resumeLock.unlock() appendLog("Returning to \(resumeBundleID)...") - let success = JITEnableContext.shared.relaunchApp(resumeBundleID) + let success: Bool + if let remoteServer { + success = JITEnableContext.shared.relaunchApp(resumeBundleID, usingRemoteServer: remoteServer) + } else { + success = JITEnableContext.shared.relaunchApp(resumeBundleID) + } guard success else { appendLog("Failed to return to \(resumeBundleID) — continuing in the foreground.") return "failed to return to \(resumeBundleID)"