-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Limit the lifetime of started WinAppDriver.exe processes (#88)
- Loading branch information
1 parent
5fac4a8
commit 7de4f58
Showing
4 changed files
with
121 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import WinSDK | ||
|
||
internal struct Win32Error: Error { | ||
public var apiName: String | ||
public var errorCode: UInt32 | ||
|
||
internal static func getLastError(apiName: String) -> Self { | ||
Self(apiName: apiName, errorCode: GetLastError()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import WinSDK | ||
|
||
/// Starts and tracks the lifetime of a process tree using Win32 APIs. | ||
internal class Win32ProcessTree { | ||
internal let jobHandle: HANDLE | ||
internal let handle: HANDLE | ||
|
||
init(path: String, args: [String]) throws { | ||
// Use a job object to ensure that the process tree doesn't outlive us. | ||
jobHandle = try Self.createJobObject() | ||
|
||
let commandLine = buildCommandLineArgsString(args: [path] + args) | ||
do { handle = try Self.createProcessInJob(commandLine: commandLine, jobHandle: jobHandle) } | ||
catch { | ||
CloseHandle(jobHandle) | ||
throw error | ||
} | ||
} | ||
|
||
func terminate() throws { | ||
if !TerminateJobObject(jobHandle, UINT.max) { | ||
throw Win32Error.getLastError(apiName: "TerminateJobObject") | ||
} | ||
} | ||
|
||
deinit { | ||
CloseHandle(handle) | ||
CloseHandle(jobHandle) | ||
} | ||
|
||
private static func createJobObject() throws -> HANDLE { | ||
guard let jobHandle = CreateJobObjectW(nil, nil) else { | ||
throw Win32Error.getLastError(apiName: "CreateJobObjectW") | ||
} | ||
|
||
var limitInfo = JOBOBJECT_EXTENDED_LIMIT_INFORMATION() | ||
limitInfo.BasicLimitInformation.LimitFlags = DWORD(JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE) | DWORD(JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK) | ||
guard SetInformationJobObject(jobHandle, JobObjectExtendedLimitInformation, | ||
&limitInfo, DWORD(MemoryLayout<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>.size)) else { | ||
defer { CloseHandle(jobHandle) } | ||
throw Win32Error.getLastError(apiName: "SetInformationJobObject") | ||
} | ||
|
||
return jobHandle | ||
} | ||
|
||
private static func createProcessInJob(commandLine: String, jobHandle: HANDLE) throws -> HANDLE { | ||
try commandLine.withCString(encodedAs: UTF16.self) { commandLine throws in | ||
var startupInfo = STARTUPINFOW() | ||
startupInfo.cb = DWORD(MemoryLayout<STARTUPINFOW>.size) | ||
|
||
var processInfo = PROCESS_INFORMATION() | ||
guard CreateProcessW( | ||
nil, | ||
UnsafeMutablePointer<WCHAR>(mutating: commandLine), | ||
nil, | ||
nil, | ||
false, | ||
DWORD(CREATE_NEW_CONSOLE) | DWORD(CREATE_SUSPENDED) | DWORD(CREATE_NEW_PROCESS_GROUP), | ||
nil, | ||
nil, | ||
&startupInfo, | ||
&processInfo | ||
) else { | ||
throw Win32Error.getLastError(apiName: "CreateProcessW") | ||
} | ||
|
||
defer { CloseHandle(processInfo.hThread) } | ||
|
||
guard AssignProcessToJobObject(jobHandle, processInfo.hProcess) else { | ||
defer { CloseHandle(processInfo.hProcess) } | ||
throw Win32Error.getLastError(apiName: "AssignProcessToJobObject") | ||
} | ||
|
||
guard ResumeThread(processInfo.hThread) != DWORD.max else { | ||
defer { CloseHandle(processInfo.hProcess) } | ||
throw Win32Error.getLastError(apiName: "ResumeThread") | ||
} | ||
|
||
return processInfo.hProcess | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.