am d9076f21: Merge "adb: Kill subprocess when the client exits."
* commit 'd9076f2132006505227e5fec91926acb512c3d68': adb: Kill subprocess when the client exits.
This commit is contained in:
commit
2017030b49
2 changed files with 37 additions and 0 deletions
|
|
@ -413,6 +413,14 @@ void Subprocess::PassDataStreams() {
|
||||||
D("closing FD %d", dead_sfd->fd());
|
D("closing FD %d", dead_sfd->fd());
|
||||||
FD_CLR(dead_sfd->fd(), &master_read_set);
|
FD_CLR(dead_sfd->fd(), &master_read_set);
|
||||||
FD_CLR(dead_sfd->fd(), &master_write_set);
|
FD_CLR(dead_sfd->fd(), &master_write_set);
|
||||||
|
if (dead_sfd == &protocol_sfd_) {
|
||||||
|
// Using SIGHUP is a decent general way to indicate that the
|
||||||
|
// controlling process is going away. If specific signals are
|
||||||
|
// needed (e.g. SIGINT), pass those through the shell protocol
|
||||||
|
// and only fall back on this for unexpected closures.
|
||||||
|
D("protocol FD died, sending SIGHUP to pid %d", pid_);
|
||||||
|
kill(pid_, SIGHUP);
|
||||||
|
}
|
||||||
dead_sfd->Reset();
|
dead_sfd->Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import posixpath
|
||||||
import random
|
import random
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
@ -196,6 +197,34 @@ class ShellTest(DeviceTest):
|
||||||
self.assertEqual('foo' + self.device.linesep, result[1])
|
self.assertEqual('foo' + self.device.linesep, result[1])
|
||||||
self.assertEqual('bar' + self.device.linesep, result[2])
|
self.assertEqual('bar' + self.device.linesep, result[2])
|
||||||
|
|
||||||
|
def test_non_interactive_sigint(self):
|
||||||
|
"""Tests that SIGINT in a non-interactive shell kills the process.
|
||||||
|
|
||||||
|
This requires the shell protocol in order to detect the broken
|
||||||
|
pipe; raw data transfer mode will only see the break once the
|
||||||
|
subprocess tries to read or write.
|
||||||
|
|
||||||
|
Bug: http://b/23825725
|
||||||
|
"""
|
||||||
|
if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
|
||||||
|
raise unittest.SkipTest('shell protocol unsupported on this device')
|
||||||
|
|
||||||
|
# Start a long-running process.
|
||||||
|
sleep_proc = subprocess.Popen(
|
||||||
|
self.device.adb_cmd + shlex.split('shell echo $$; sleep 60'),
|
||||||
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
remote_pid = sleep_proc.stdout.readline().strip()
|
||||||
|
self.assertIsNone(sleep_proc.returncode, 'subprocess terminated early')
|
||||||
|
proc_query = shlex.split('ps {0} | grep {0}'.format(remote_pid))
|
||||||
|
|
||||||
|
# Verify that the process is running, send signal, verify it stopped.
|
||||||
|
self.device.shell(proc_query)
|
||||||
|
os.kill(sleep_proc.pid, signal.SIGINT)
|
||||||
|
sleep_proc.communicate()
|
||||||
|
self.assertEqual(1, self.device.shell_nocheck(proc_query)[0],
|
||||||
|
'subprocess failed to terminate')
|
||||||
|
|
||||||
|
|
||||||
class ArgumentEscapingTest(DeviceTest):
|
class ArgumentEscapingTest(DeviceTest):
|
||||||
def test_shell_escaping(self):
|
def test_shell_escaping(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue