mirror of
https://github.com/StikDebug/StikDebug.git
synced 2026-10-15 20:10:30 +00:00
Return to the target app after attaching for JIT
This commit is contained in:
parent
c5b23e2282
commit
5e0e48d4e6
3 changed files with 81 additions and 8 deletions
|
|
@ -642,6 +642,31 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
emitLog("Returned to \(bundleID) (PID \(pid))", logger: logger)
|
||||
return true
|
||||
} catch {
|
||||
emitLog("Failed to return to \(bundleID): \(error.localizedDescription)", logger: logger)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func startSyslogRelay(handler: @escaping SyslogLineHandler, onError: @escaping SyslogErrorHandler) {
|
||||
do {
|
||||
try ensureTunnel()
|
||||
|
|
|
|||
|
|
@ -22,12 +22,17 @@ final class RunJSViewModel: ObservableObject, Identifiable, @unchecked Sendable
|
|||
var debugProxy: OpaquePointer?
|
||||
var remoteServer: OpaquePointer?
|
||||
var semaphore: DispatchSemaphore?
|
||||
|
||||
init(pid: Int, debugProxy: OpaquePointer?, remoteServer: OpaquePointer?, semaphore: DispatchSemaphore?) {
|
||||
let resumeBundleID: String?
|
||||
|
||||
private let resumeLock = NSLock()
|
||||
private var hasResumedApp = false
|
||||
|
||||
init(pid: Int, debugProxy: OpaquePointer?, remoteServer: OpaquePointer?, semaphore: DispatchSemaphore?, resumeBundleID: String? = nil) {
|
||||
self.pid = pid
|
||||
self.debugProxy = debugProxy
|
||||
self.remoteServer = remoteServer
|
||||
self.semaphore = semaphore
|
||||
self.resumeBundleID = resumeBundleID
|
||||
}
|
||||
|
||||
func runScript(path: URL, scriptName: String? = nil) throws {
|
||||
|
|
@ -57,8 +62,14 @@ final class RunJSViewModel: ObservableObject, Identifiable, @unchecked Sendable
|
|||
self.context?.exception = JSValue(object: "Script execution is interrupted by StikDebug.", in: self.context!)
|
||||
return ""
|
||||
}
|
||||
|
||||
return handleJSContextSendDebugCommand(self.context, commandStr, self.debugProxy) ?? ""
|
||||
|
||||
let response = handleJSContextSendDebugCommand(self.context, commandStr, self.debugProxy) ?? ""
|
||||
|
||||
if commandStr.hasPrefix("vAttach"), response.hasPrefix("T") {
|
||||
self.resumeTargetApp()
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
let logFunction: @convention(block) (String) -> Void = { logStr in
|
||||
|
|
@ -78,8 +89,13 @@ final class RunJSViewModel: ObservableObject, Identifiable, @unchecked Sendable
|
|||
let hasTXMFunction: @convention(block) () -> Bool = {
|
||||
return ProcessInfo.processInfo.hasTXM
|
||||
}
|
||||
|
||||
|
||||
let resumeAppFunction: @convention(block) () -> String = {
|
||||
return self.resumeTargetApp()
|
||||
}
|
||||
|
||||
context = JSContext()
|
||||
context?.setObject(resumeAppFunction, forKeyedSubscript: "resume_app" as NSString)
|
||||
context?.setObject(hasTXMFunction, forKeyedSubscript: "hasTXM" as NSString)
|
||||
context?.setObject(getPidFunction, forKeyedSubscript: "get_pid" as NSString)
|
||||
context?.setObject(sendCommandFunction, forKeyedSubscript: "send_command" as NSString)
|
||||
|
|
@ -101,6 +117,35 @@ final class RunJSViewModel: ObservableObject, Identifiable, @unchecked Sendable
|
|||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func resumeTargetApp() -> String {
|
||||
resumeLock.lock()
|
||||
if hasResumedApp {
|
||||
resumeLock.unlock()
|
||||
return "OK"
|
||||
}
|
||||
guard let resumeBundleID else {
|
||||
resumeLock.unlock()
|
||||
return "no app to return to for this session"
|
||||
}
|
||||
hasResumedApp = true
|
||||
resumeLock.unlock()
|
||||
|
||||
appendLog("Returning to \(resumeBundleID)...")
|
||||
let success = JITEnableContext.shared.relaunchApp(resumeBundleID)
|
||||
guard success else {
|
||||
appendLog("Failed to return to \(resumeBundleID) — continuing in the foreground.")
|
||||
return "failed to return to \(resumeBundleID)"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
|
||||
private func appendLog(_ message: String) {
|
||||
DispatchQueue.main.async {
|
||||
self.logs.append(message)
|
||||
}
|
||||
}
|
||||
|
||||
private func captureScreenshot(named preferredName: String?) -> String {
|
||||
if executionInterrupted {
|
||||
raiseException("Script execution is interrupted by StikDebug.")
|
||||
|
|
|
|||
|
|
@ -259,12 +259,13 @@ struct HomeView: View {
|
|||
.accessibilityLabel(feedback.message)
|
||||
}
|
||||
|
||||
private func getJsCallback(_ script: Data, name: String? = nil) -> DebugAppCallback {
|
||||
private func getJsCallback(_ script: Data, name: String? = nil, resumeBundleID: String? = nil) -> DebugAppCallback {
|
||||
return { pid, debugProxyHandle, remoteServerHandle, semaphore in
|
||||
let model = RunJSViewModel(pid: Int(pid),
|
||||
debugProxy: debugProxyHandle,
|
||||
remoteServer: remoteServerHandle,
|
||||
semaphore: semaphore)
|
||||
semaphore: semaphore,
|
||||
resumeBundleID: resumeBundleID)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
scriptRunModel = model
|
||||
|
|
@ -338,9 +339,11 @@ struct HomeView: View {
|
|||
scriptData = preferred.data
|
||||
}
|
||||
|
||||
let resumeBundleID = pid == nil ? nil : bundleID
|
||||
|
||||
var callback: DebugAppCallback? = nil
|
||||
if ProcessInfo.processInfo.hasTXM, let sd = scriptData {
|
||||
callback = getJsCallback(sd, name: scriptName ?? bundleID ?? "Script")
|
||||
callback = getJsCallback(sd, name: scriptName ?? bundleID ?? "Script", resumeBundleID: resumeBundleID)
|
||||
}
|
||||
|
||||
var lastDebugMessage: String?
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue