@@ -312,32 +312,17 @@ export class ChromeDebugAdapter extends CoreDebugAdapter {
312312 super . onResumed ( ) ;
313313 }
314314
315- public disconnect ( args : DebugProtocol . DisconnectArguments ) : void {
315+ public async disconnect ( args : DebugProtocol . DisconnectArguments ) : Promise < void > {
316316 const hadTerminated = this . _hasTerminated ;
317317
318318 // Disconnect before killing Chrome, because running "taskkill" when it's paused sometimes doesn't kill it
319319 super . disconnect ( args ) ;
320320
321- if ( ( this . _chromeProc || ( ! this . _chromeProc && this . _chromePID ) ) && ! hadTerminated ) {
321+ if ( ( this . _chromeProc || this . _chromePID ) && ! hadTerminated ) {
322322 // Only kill Chrome if the 'disconnect' originated from vscode. If we previously terminated
323323 // due to Chrome shutting down, or devtools taking over, don't kill Chrome.
324324 if ( coreUtils . getPlatform ( ) === coreUtils . Platform . Windows && this . _chromePID ) {
325- let taskkillCmd = `taskkill /PID ${ this . _chromePID } ` ;
326- logger . log ( `Killing Chrome process by pid: ${ taskkillCmd } ` ) ;
327- try {
328- // Run synchronously because this process may be killed before exec() would run
329- execSync ( taskkillCmd ) ;
330- } catch ( e ) {
331- // Can fail if Chrome was already open, and the process with _chromePID is gone.
332- // Or if it already shut down for some reason.
333- }
334- // execSync above may succeed, but Chrome still might not shut down, for example if the web page promts the user about unsaved changes.
335- // In that case, we need to use /F to force shutdown, but we risk Chrome not shutting down correctly.
336- taskkillCmd = `taskkill /F /PID ${ this . _chromePID } ` ;
337- logger . log ( `Killing Chrome process by pid (using force in case the first attempt failed): ${ taskkillCmd } ` ) ;
338- try {
339- execSync ( taskkillCmd ) ;
340- } catch ( e ) { }
325+ await this . killChromeOnWindows ( this . _chromePID ) ;
341326 } else if ( this . _chromeProc ) {
342327 logger . log ( 'Killing Chrome process' ) ;
343328 this . _chromeProc . kill ( 'SIGINT' ) ;
@@ -347,6 +332,44 @@ export class ChromeDebugAdapter extends CoreDebugAdapter {
347332 this . _chromeProc = null ;
348333 }
349334
335+ private async killChromeOnWindows ( chromePID : number ) : Promise < void > {
336+ let taskkillCmd = `taskkill /PID ${ chromePID } ` ;
337+ logger . log ( `Killing Chrome process by pid: ${ taskkillCmd } ` ) ;
338+ try {
339+ execSync ( taskkillCmd ) ;
340+ } catch ( e ) {
341+ // The command will fail if process was not found. This can be safely ignored.
342+ }
343+
344+ for ( let i = 0 ; i < 10 ; i ++ ) {
345+ // Check to see if the process is still running, with CSV output format
346+ let tasklistCmd = `tasklist /FI "PID eq ${ chromePID } " /FO CSV` ;
347+ logger . log ( `Looking up process by pid: ${ tasklistCmd } ` ) ;
348+ let tasklistOutput = execSync ( tasklistCmd ) . toString ( ) ;
349+
350+ // If the process is found, tasklist will output CSV with one of the values being the PID. Exit code will be 0.
351+ // If the process is not found, tasklist will give a generic "not found" message instead. Exit code will also be 0.
352+ // If we see an entry in the CSV for the PID, then we can assume the process was found.
353+ if ( ! tasklistOutput . includes ( `"${ chromePID } "` ) ) {
354+ logger . log ( `Chrome process with pid ${ chromePID } is not running` ) ;
355+ return ;
356+ }
357+
358+ // Give the process some time to close gracefully
359+ logger . log ( `Chrome process with pid ${ chromePID } is still alive, waiting...` ) ;
360+ await new Promise < void > ( ( resolve ) => {
361+ setTimeout ( resolve , 200 ) ;
362+ } ) ;
363+ }
364+
365+ // At this point we can assume the process won't close on its own, so force kill it
366+ let taskkillForceCmd = `taskkill /F /PID ${ chromePID } ` ;
367+ logger . log ( `Killing Chrome process timed out. Killing again using force: ${ taskkillForceCmd } ` ) ;
368+ try {
369+ execSync ( taskkillForceCmd ) ;
370+ } catch ( e ) { }
371+ }
372+
350373 /**
351374 * Opt-in event called when the 'reload' button in the debug widget is pressed
352375 */
0 commit comments