Commit 84436c8e authored by perezju's avatar perezju Committed by Commit bot

[Android] Add a "quiet" flag so KillAll doesn't complain if no processes killed

This makes it easier to write what turns out to be the most
common usage of this method: ensure that some processes
are not running, and don't care if none is found.

Also helps to distinguish an adb/device error (which should
trigger a retry), from cases where no processes to kill are found
(where the caller doesn't need/want to retry).

Clients that benefit from this flag are also updated.

BUG=475845

Review URL: https://codereview.chromium.org/1079113002

Cr-Commit-Position: refs/heads/master@{#325217}
parent 67874ebf
......@@ -232,14 +232,7 @@ def _PushAndLaunchAdbReboot(device, target):
"""
logging.info('Will push and launch adb_reboot on %s' % str(device))
# Kill if adb_reboot is already running.
try:
# Don't try to kill adb_reboot more than once. We don't expect it to be
# running at all.
device.KillAll('adb_reboot', blocking=True, timeout=2, retries=0)
except device_errors.CommandFailedError:
# We can safely ignore the exception because we don't expect adb_reboot
# to be running.
pass
device.KillAll('adb_reboot', blocking=True, timeout=2, quiet=True)
# Push adb_reboot
logging.info(' Pushing adb_reboot ...')
adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT,
......
......@@ -25,6 +25,7 @@ import zipfile
import pylib.android_commands
from pylib import cmd_helper
from pylib import constants
from pylib import device_signal
from pylib.device import adb_wrapper
from pylib.device import decorators
from pylib.device import device_blacklist
......@@ -575,37 +576,46 @@ class DeviceUtils(object):
return output
@decorators.WithTimeoutAndRetriesFromInstance()
def KillAll(self, process_name, signum=9, as_root=False, blocking=False,
timeout=None, retries=None):
def KillAll(self, process_name, signum=device_signal.SIGKILL, as_root=False,
blocking=False, quiet=False, timeout=None, retries=None):
"""Kill all processes with the given name on the device.
Args:
process_name: A string containing the name of the process to kill.
signum: An integer containing the signal number to send to kill. Defaults
to 9 (SIGKILL).
to SIGKILL (9).
as_root: A boolean indicating whether the kill should be executed with
root privileges.
blocking: A boolean indicating whether we should wait until all processes
with the given |process_name| are dead.
quiet: A boolean indicating whether to ignore the fact that no processes
to kill were found.
timeout: timeout in seconds
retries: number of retries
Returns:
The number of processes attempted to kill.
Raises:
CommandFailedError if no process was killed.
CommandFailedError if no process was killed and |quiet| is False.
CommandTimeoutError on timeout.
DeviceUnreachableError on missing device.
"""
pids = self._GetPidsImpl(process_name)
pids = self.GetPids(process_name)
if not pids:
raise device_errors.CommandFailedError(
'No process "%s"' % process_name, str(self))
if quiet:
return 0
else:
raise device_errors.CommandFailedError(
'No process "%s"' % process_name, str(self))
cmd = ['kill', '-%d' % signum] + pids.values()
self.RunShellCommand(cmd, as_root=as_root, check_return=True)
if blocking:
# TODO(perezu): use timeout_retry.WaitFor
wait_period = 0.1
while self._GetPidsImpl(process_name):
while self.GetPids(process_name):
time.sleep(wait_period)
return len(pids)
......@@ -1355,9 +1365,6 @@ class DeviceUtils(object):
CommandTimeoutError on timeout.
DeviceUnreachableError on missing device.
"""
return self._GetPidsImpl(process_name)
def _GetPidsImpl(self, process_name):
procs_pids = {}
for line in self.RunShellCommand('ps', check_return=True):
try:
......
......@@ -16,13 +16,13 @@ import datetime
import logging
import os
import re
import signal
import sys
import unittest
from pylib import android_commands
from pylib import cmd_helper
from pylib import constants
from pylib import device_signal
from pylib.device import adb_wrapper
from pylib.device import device_errors
from pylib.device import device_utils
......@@ -641,40 +641,34 @@ class DeviceUtilsGetDevicePieWrapper(DeviceUtilsTest):
@mock.patch('time.sleep', mock.Mock())
class DeviceUtilsKillAllTest(DeviceUtilsTest):
def testKillAll_noMatchingProcesses(self):
with self.assertCall(self.call.adb.Shell('ps'),
'USER PID PPID VSIZE RSS WCHAN PC NAME\n'):
def testKillAll_noMatchingProcessesFailure(self):
with self.assertCall(self.call.device.GetPids('test_process'), {}):
with self.assertRaises(device_errors.CommandFailedError):
self.device.KillAll('test_process')
def testKillAll_noMatchingProcessesQuiet(self):
with self.assertCall(self.call.device.GetPids('test_process'), {}):
self.assertEqual(0, self.device.KillAll('test_process', quiet=True))
def testKillAll_nonblocking(self):
with self.assertCalls(
(self.call.adb.Shell('ps'),
'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
(self.call.device.GetPids('some.process'), {'some.process': '1234'}),
(self.call.adb.Shell('kill -9 1234'), '')):
self.assertEquals(1,
self.device.KillAll('some.process', blocking=False))
def testKillAll_blocking(self):
with self.assertCalls(
(self.call.adb.Shell('ps'),
'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
(self.call.device.GetPids('some.process'), {'some.process': '1234'}),
(self.call.adb.Shell('kill -9 1234'), ''),
(self.call.adb.Shell('ps'),
'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
(self.call.adb.Shell('ps'),
'USER PID PPID VSIZE RSS WCHAN PC NAME\n')):
(self.call.device.GetPids('some.process'), {'some.process': '1234'}),
(self.call.device.GetPids('some.process'), {})):
self.assertEquals(1,
self.device.KillAll('some.process', blocking=True))
def testKillAll_root(self):
with self.assertCalls(
(self.call.adb.Shell('ps'),
'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
(self.call.device.GetPids('some.process'), {'some.process': '1234'}),
(self.call.device.NeedsSU(), True),
(self.call.adb.Shell("su -c sh -c 'kill -9 1234'"), '')):
self.assertEquals(1,
......@@ -682,12 +676,10 @@ class DeviceUtilsKillAllTest(DeviceUtilsTest):
def testKillAll_sigterm(self):
with self.assertCalls(
(self.call.adb.Shell('ps'),
'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
(self.call.device.GetPids('some.process'), {'some.process': '1234'}),
(self.call.adb.Shell('kill -15 1234'), '')):
self.assertEquals(1,
self.device.KillAll('some.process', signum=signal.SIGTERM))
self.device.KillAll('some.process', signum=device_signal.SIGTERM))
class DeviceUtilsStartActivityTest(DeviceUtilsTest):
......
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Defines constants for signals that should be supported on devices.
Note: Obtained by running `kill -l` on a user device.
"""
SIGHUP = 1 # Hangup
SIGINT = 2 # Interrupt
SIGQUIT = 3 # Quit
SIGILL = 4 # Illegal instruction
SIGTRAP = 5 # Trap
SIGABRT = 6 # Aborted
SIGBUS = 7 # Bus error
SIGFPE = 8 # Floating point exception
SIGKILL = 9 # Killed
SIGUSR1 = 10 # User signal 1
SIGSEGV = 11 # Segmentation fault
SIGUSR2 = 12 # User signal 2
SIGPIPE = 13 # Broken pipe
SIGALRM = 14 # Alarm clock
SIGTERM = 15 # Terminated
SIGSTKFLT = 16 # Stack fault
SIGCHLD = 17 # Child exited
SIGCONT = 18 # Continue
SIGSTOP = 19 # Stopped (signal)
SIGTSTP = 20 # Stopped
SIGTTIN = 21 # Stopped (tty input)
SIGTTOU = 22 # Stopped (tty output)
SIGURG = 23 # Urgent I/O condition
SIGXCPU = 24 # CPU time limit exceeded
SIGXFSZ = 25 # File size limit exceeded
SIGVTALRM = 26 # Virtual timer expired
SIGPROF = 27 # Profiling timer expired
SIGWINCH = 28 # Window size changed
SIGIO = 29 # I/O possible
SIGPWR = 30 # Power failure
SIGSYS = 31 # Bad system call
......@@ -112,12 +112,7 @@ class _ExeDelegate(object):
return output
def Clear(self, device):
try:
device.KillAll(self._exe_file_name, blocking=True, timeout=30, retries=0)
except device_errors.CommandFailedError:
# Raised if there is no process with the given name, which in this case
# is all we care about.
pass
device.KillAll(self._exe_file_name, blocking=True, timeout=30, quiet=True)
class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
......
......@@ -79,15 +79,7 @@ class TestPackageExecutable(TestPackage):
#override
def ClearApplicationState(self, device):
try:
# We don't expect the executable to be running, so we don't attempt
# to retry on failure.
device.KillAll(self.suite_name, blocking=True, timeout=30, retries=0)
except device_errors.CommandFailedError:
# KillAll raises an exception if it can't find a process with the given
# name. We only care that there is no process with the given name, so
# we can safely eat the exception.
pass
device.KillAll(self.suite_name, blocking=True, timeout=30, quiet=True)
#override
def CreateCommandLineFileOnDevice(self, device, test_filter, test_arguments):
......
......@@ -4,11 +4,11 @@
import logging
import os
import signal
import tempfile
import time
from pylib import cmd_helper
from pylib import device_signal
from pylib.device import device_errors
# TODO(jbudorick) Remove once telemetry gets switched over.
......@@ -74,9 +74,8 @@ class VideoRecorder(object):
self._is_started = False
if not self._recorder:
return
try:
self._device.KillAll('screenrecord', signum=signal.SIGINT)
except device_errors.CommandFailedError:
if not self._device.KillAll('screenrecord', signum=device_signal.SIGINT,
quiet=True):
logging.warning('Nothing to kill: screenrecord was not running')
self._recorder.wait()
......
......@@ -262,17 +262,14 @@ class AndroidPlatformBackend(
self._device.ForceStop(application)
def KillApplication(self, application):
"""Kill the given application.
"""Kill the given |application|.
Might be used instead of ForceStop for efficiency reasons.
Args:
application: The full package name string of the application to kill.
"""
# We use KillAll rather than ForceStop for efficiency reasons.
try:
self._adb.device().KillAll(application, retries=0)
time.sleep(3)
except device_errors.CommandFailedError:
pass
self._device.KillAll(application, blocking=True, quiet=True)
def LaunchApplication(
self, application, parameters=None, elevate_privilege=False):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment