# Copyright 2015 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import collections import time from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib import utils # Use this with ProcessWatcher to start your process in a minijail. This # is useful for instance if you would like to drop autotest's default root # priviledges. Both fields must be set to valid users/groups. MinijailConfig = collections.namedtuple('MinijailConfig', ['user', 'group']) class ProcessWatcher(object): """Start a process, and terminate it later.""" def __init__(self, command, args=tuple(), minijail_config=None, host=None): """Construst a ProcessWatcher without starting the process. @param command: string command to use to start the process. @param args: list of strings to pass to the command. @param minijail_config: MinijailConfig tuple defined above. @param host: host object if the server should be started on a remote host. """ self._command = ' '.join([command] + list(args)) if '"' in self._command: raise error.TestError('Please implement shell escaping in ' 'ProcessWatcher.') self._minijail_config = minijail_config self._run = utils.run if host is None else host.run def start(self): """Start a (potentially remote) instance of the process.""" command = self._command prefix = '' if self._minijail_config is not None: prefix = 'minijail0 -i -g %s -u %s ' % (self._minijail_config.group, self._minijail_config.user) # Redirect output streams to avoid odd interactions between autotest's # shell environment and the command's runtime environment. self._run('%s%s >/dev/null 2>&1 &' % (prefix, self._command)) def close(self, timeout_seconds=40): """Close the (potentially remote) instance of the process. @param timeout_seconds: int number of seconds to wait for shutdown. """ self._run('pkill -f --signal TERM "%s"' % self._command, ignore_status=True) start_time = time.time() while time.time() - start_time < timeout_seconds: result = self._run('pgrep -f -l "%s"' % self._command, ignore_status=True) if result.exit_status != 0: return time.sleep(0.3) raise error.TestError('Timed out waiting for %s to die.' % self._command)