Loading adb/shell_service.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -413,6 +413,14 @@ void Subprocess::PassDataStreams() { D("closing FD %d", dead_sfd->fd()); FD_CLR(dead_sfd->fd(), &master_read_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(); } } Loading adb/test_device.py +29 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import posixpath import random import shlex import shutil import signal import subprocess import tempfile import unittest Loading Loading @@ -196,6 +197,34 @@ class ShellTest(DeviceTest): self.assertEqual('foo' + self.device.linesep, result[1]) 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): def test_shell_escaping(self): Loading Loading
adb/shell_service.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -413,6 +413,14 @@ void Subprocess::PassDataStreams() { D("closing FD %d", dead_sfd->fd()); FD_CLR(dead_sfd->fd(), &master_read_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(); } } Loading
adb/test_device.py +29 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import posixpath import random import shlex import shutil import signal import subprocess import tempfile import unittest Loading Loading @@ -196,6 +197,34 @@ class ShellTest(DeviceTest): self.assertEqual('foo' + self.device.linesep, result[1]) 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): def test_shell_escaping(self): Loading