def _ExecuteOneShellCommandWithTimeout(cmd, timeout, callback_on_timeout=None, *args): """Executes a command with timeout. If the process times out, this function terminates it and continues waiting. Args: proc: Popen object, the process to wait for. timeout: float, timeout in seconds. callback_on_timeout: callable, callback function for the case when the command times out. args: arguments for the callback_on_timeout. Returns: tuple(string, string, int) which are stdout, stderr and return code. """ # On Windows, subprocess.Popen(shell=True) starts two processes, cmd.exe # and the command. The Popen object represents the cmd.exe process, so # calling Popen.kill() does not terminate the command. # This function uses process group to ensure command termination. proc = utils.start_standing_subprocess(cmd) result = [] def WaitForProcess(): out, err = proc.communicate() result.append((out, err, proc.returncode)) wait_thread = threading.Thread(target=WaitForProcess) wait_thread.daemon = True wait_thread.start() try: wait_thread.join(timeout) finally: if proc.poll() is None: utils.kill_process_group(proc) if callback_on_timeout is not None: if ((utils.is_on_windows() and proc.returncode == EXIT_CODE_TIMEOUT_ON_WINDOWS) or proc.returncode == EXIT_CODE_TIMEOUT_ON_LINUX): callback_on_timeout(*args) wait_thread.join() if len(result) != 1: logging.error("Unexpected command result: %s", result) return "", "", proc.returncode return result[0]
def startAdbLogcat(self): """Starts a standing adb logcat collection in separate subprocesses and save the logcat in a file. """ if self.isAdbLogcatOn: raise AndroidDeviceError(("Android device %s already has an adb " "logcat thread going on. Cannot start " "another one.") % self.serial) f_name = "adblog,%s,%s.txt" % (self.model, self.serial) utils.create_dir(self.log_path) logcat_file_path = os.path.join(self.log_path, f_name) try: extra_params = self.adb_logcat_param except AttributeError: extra_params = "-b all" cmd = "adb -s %s logcat -v threadtime %s >> %s" % ( self.serial, extra_params, logcat_file_path) self.adb_logcat_process = utils.start_standing_subprocess(cmd) self.adb_logcat_file_path = logcat_file_path
def startVtsAgent(self): """Start HAL agent on the AndroidDevice. This function starts the target side native agent and is persisted throughout the test run. """ self.log.info("Starting VTS agent") if self.vts_agent_process: raise AndroidDeviceError("HAL agent is already running on %s." % self.serial) event = tfi.Begin("start vts agent", tfi.categories.FRAMEWORK_SETUP) self._StopLLKD() event_cleanup = tfi.Begin("start vts agent -- cleanup", tfi.categories.FRAMEWORK_SETUP) cleanup_commands = [ "rm -f /data/local/tmp/vts_driver_*", "rm -f /data/local/tmp/vts_agent_callback*" ] kill_command = "pgrep 'vts_*' | xargs kill" cleanup_commands.append(kill_command) try: self.adb.shell("\"" + " ; ".join(cleanup_commands) + "\"") except adb.AdbError as e: self.log.warning( "A command to setup the env to start the VTS Agent failed %s", e) event_cleanup.End() log_severity = getattr(self, keys.ConfigKeys.KEY_LOG_SEVERITY, "INFO") bits = ['64', '32'] if self.is64Bit else ['32'] file_names = ['vts_hal_agent', 'vts_hal_driver', 'vts_shell_driver'] for bitness in bits: vts_agent_log_path = os.path.join( self.log_path, 'vts_agent_%s_%s.log' % (bitness, self.serial)) chmod_cmd = ' '.join( map( lambda file_name: 'chmod 755 {path}/{bit}/{file_name}{bit};'.format( path=DEFAULT_AGENT_BASE_DIR, bit=bitness, file_name=file_name), file_names)) cmd = ( 'adb -s {s} shell "{chmod} LD_LIBRARY_PATH={path}/{bitness} ' '{path}/{bitness}/vts_hal_agent{bitness} ' '--hal_driver_path_32={path}/32/vts_hal_driver32 ' '--hal_driver_path_64={path}/64/vts_hal_driver64 ' '--spec_dir={path}/spec ' '--shell_driver_path_32={path}/32/vts_shell_driver32 ' '--shell_driver_path_64={path}/64/vts_shell_driver64 ' '-l {severity}" >> {log} 2>&1').format( s=self.serial, chmod=chmod_cmd, bitness=bitness, path=DEFAULT_AGENT_BASE_DIR, log=vts_agent_log_path, severity=log_severity) try: self.vts_agent_process = utils.start_standing_subprocess( cmd, check_health_delay=1) break except utils.VTSUtilsError as e: logging.exception(e) with open(vts_agent_log_path, 'r') as log_file: logging.error("VTS agent output:\n") logging.error(log_file.read()) # one common cause is that 64-bit executable is not supported # in low API level devices. if bitness == '32': msg = "unrecognized bitness" event.Remove(msg) logging.error(msg) raise else: logging.error('retrying using a 32-bit binary.') event.End()
def startVtsAgent(self): """Start HAL agent on the AndroidDevice. This function starts the target side native agent and is persisted throughout the test run. """ self.log.info("Starting VTS agent") if self.vts_agent_process: raise AndroidDeviceError("HAL agent is already running on %s." % self.serial) cleanup_commands = [ "rm -f /data/local/tmp/vts_driver_*", "rm -f /data/local/tmp/vts_agent_callback*" ] kill_commands = ["killall vts_hal_agent32", "killall vts_hal_agent64", "killall fuzzer32", "killall fuzzer64", "killall vts_shell_driver32", "killall vts_shell_driver64"] cleanup_commands.extend(kill_commands) chmod_commands = [ "chmod 755 %s/32/vts_hal_agent32" % DEFAULT_AGENT_BASE_DIR, "chmod 755 %s/64/vts_hal_agent64" % DEFAULT_AGENT_BASE_DIR, "chmod 755 %s/32/fuzzer32" % DEFAULT_AGENT_BASE_DIR, "chmod 755 %s/64/fuzzer64" % DEFAULT_AGENT_BASE_DIR, "chmod 755 %s/32/vts_shell_driver32" % DEFAULT_AGENT_BASE_DIR, "chmod 755 %s/64/vts_shell_driver64" % DEFAULT_AGENT_BASE_DIR ] cleanup_commands.extend(chmod_commands) for cmd in cleanup_commands: try: self.adb.shell(cmd) except adb.AdbError as e: self.log.warning( "A command to setup the env to start the VTS Agent failed %s", e) bits = ['64', '32'] if self.is64Bit else ['32'] for bitness in bits: vts_agent_log_path = os.path.join(self.log_path, "vts_agent_" + bitness + ".log") cmd = ( 'adb -s {s} shell LD_LIBRARY_PATH={path}/{bitness} ' '{path}/{bitness}/vts_hal_agent{bitness}' ' {path}/32/fuzzer32 {path}/64/fuzzer64 {path}/spec' ' {path}/32/vts_shell_driver32 {path}/64/vts_shell_driver64 >> {log} 2>&1' ).format(s=self.serial, bitness=bitness, path=DEFAULT_AGENT_BASE_DIR, log=vts_agent_log_path) try: self.vts_agent_process = utils.start_standing_subprocess( cmd, check_health_delay=1) break except utils.VTSUtilsError as e: logging.exception(e) with open(vts_agent_log_path, 'r') as log_file: logging.error("VTS agent output:\n") logging.error(log_file.read()) # one common cause is that 64-bit executable is not supported # in low API level devices. if bitness == '32': raise else: logging.error('retrying using a 32-bit binary.')