def FinishProvisioning(device, options): # The lockscreen can't be disabled on user builds, so send a keyevent # to unlock it. if device.IsUserBuild(): device.SendKeyEvent(keyevent.KEYCODE_MENU) if options.min_battery_level is not None: try: battery = battery_utils.BatteryUtils(device) battery.ChargeDeviceToLevel(options.min_battery_level) except device_errors.CommandFailedError: logging.exception('Unable to charge device to specified level.') if options.max_battery_temp is not None: try: battery = battery_utils.BatteryUtils(device) battery.LetBatteryCoolToTemperature(options.max_battery_temp) except device_errors.CommandFailedError: logging.exception('Unable to let battery cool to specified temperature.') def _set_and_verify_date(): if device.build_version_sdk >= version_codes.MARSHMALLOW: date_format = '%m%d%H%M%Y.%S' set_date_command = ['date'] else: date_format = '%Y%m%d.%H%M%S' set_date_command = ['date', '-s'] strgmtime = time.strftime(date_format, time.gmtime()) set_date_command.append(strgmtime) device.RunShellCommand(set_date_command, as_root=True, check_return=True) device_time = device.RunShellCommand( ['date', '+"%Y%m%d.%H%M%S"'], as_root=True, single_line=True).replace('"', '') device_time = datetime.datetime.strptime(device_time, "%Y%m%d.%H%M%S") correct_time = datetime.datetime.strptime(strgmtime, date_format) tdelta = (correct_time - device_time).seconds if tdelta <= 1: logging.info('Date/time successfully set on %s', device) return True else: logging.error('Date mismatch. Device: %s Correct: %s', device_time.isoformat(), correct_time.isoformat()) return False # Sometimes the date is not set correctly on the devices. Retry on failure. if device.IsUserBuild(): # TODO(bpastene): Figure out how to set the date & time on user builds. pass else: if not timeout_retry.WaitFor( _set_and_verify_date, wait_period=1, max_tries=2): raise device_errors.CommandFailedError( 'Failed to set date & time.', device_serial=str(device)) props = device.RunShellCommand('getprop', check_return=True) for prop in props: logging.info(' %s', prop) if options.auto_reconnect: _PushAndLaunchAdbReboot(device, options.target)
def WaitForFastbootMode(self, timeout=None, retries=None): """Wait for device to boot into fastboot mode. This waits for the device serial to show up in fastboot devices output. """ timeout_retry.WaitFor(self.IsFastbootMode, wait_period=self._FASTBOOT_WAIT_TIME)
def LetBatteryCoolToTemperature(self, target_temp, wait_period=180): """Lets device sit to give battery time to cool down Args: temp: maximum temperature to allow in tenths of degrees c. wait_period: time in seconds to wait between checking. """ def cool_device(): temp = self.GetBatteryInfo().get('temperature') if temp is None: logger.warning('Unable to find current battery temperature.') temp = 0 else: logger.info('Current battery temperature: %s', temp) if int(temp) <= target_temp: return True else: if 'Nexus 5' in self._cache['profile']['name']: self._DischargeDevice(1) return False self._DiscoverDeviceProfile() self.EnableBatteryUpdates() logger.info('Waiting for the device to cool down to %s (0.1 C)', target_temp) timeout_retry.WaitFor(cool_device, wait_period=wait_period)
def _HardwareSetCharging(self, enabled, timeout=None, retries=None): """Enables or disables charging on the device. Args: enabled: A boolean indicating whether charging should be enabled or disabled. timeout: timeout in seconds retries: number of retries Raises: device_errors.CommandFailedError: If method of disabling charging cannot be determined. """ self._DiscoverDeviceProfile() if not self._cache['profile']['enable_command']: raise device_errors.CommandFailedError( 'Unable to find charging commands.') command = (self._cache['profile']['enable_command'] if enabled else self._cache['profile']['disable_command']) def verify_charging(): return self.GetCharging() == enabled self._device.RunShellCommand(command, shell=True, check_return=True, as_root=True, large_output=True) timeout_retry.WaitFor(verify_charging, wait_period=1)
def _DischargeDevice(self, percent, wait_period=120): """Disables charging and waits for device to discharge given amount Args: percent: level of charge to discharge. Raises: ValueError: If percent is not between 1 and 99. """ battery_level = int(self.GetBatteryInfo().get('level')) if not 0 < percent < 100: raise ValueError('Discharge amount(%s) must be between 1 and 99' % percent) if battery_level is None: logger.warning('Unable to find current battery level. Cannot discharge.') return # Do not discharge if it would make battery level too low. if percent >= battery_level - 10: logger.warning('Battery is too low or discharge amount requested is too ' 'high. Cannot discharge phone %s percent.', percent) return self._HardwareSetCharging(False) def device_discharged(): self._HardwareSetCharging(True) current_level = int(self.GetBatteryInfo().get('level')) logger.info('current battery level: %s', current_level) if battery_level - current_level >= percent: return True self._HardwareSetCharging(False) return False timeout_retry.WaitFor(device_discharged, wait_period=wait_period)
def main(): logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser( description='Fetches Crashpad dumps from a given device, ' 'walks and symbolizes the stacks.') parser.add_argument('--device', required=True, help='Device serial number') parser.add_argument('--adb-path', required=True, help='Path to the "adb" command') parser.add_argument( '--build-path', required=True, help='Build output directory, equivalent to CHROMIUM_OUTPUT_DIR') parser.add_argument( '--chrome-cache-path', required=True, help='Directory on the device where Chrome stores cached files,' ' crashpad stores dumps in a subdirectory of it') args = parser.parse_args() stackwalk_path = os.path.join(args.build_path, 'minidump_stackwalk') if not os.path.exists(stackwalk_path): logging.error('Missing minidump_stackwalk executable') return 1 devil_chromium.Initialize(adb_path=args.adb_path) device = device_utils.DeviceUtils(args.device) device_crashpad_path = posixpath.join(args.chrome_cache_path, 'Crashpad', 'pending') def CrashpadDumpExists(): return _ChooseLatestCrashpadDump(device, device_crashpad_path) crashpad_file = timeout_retry.WaitFor(CrashpadDumpExists, wait_period=1, max_tries=9) if not crashpad_file: logging.error('Could not locate a crashpad dump') return 1 dump_dir = tempfile.mkdtemp() symbols_dir = None try: device.PullFile(device_path=posixpath.join(device_crashpad_path, crashpad_file), host_path=dump_dir) dump_full_path = os.path.join(dump_dir, crashpad_file) library_names = _ExtractLibraryNamesFromDump(args.build_path, dump_full_path) symbols_dir = _CreateSymbolsDir(args.build_path, library_names) stackwalk_cmd = [stackwalk_path, dump_full_path, symbols_dir] subprocess.call(stackwalk_cmd) finally: shutil.rmtree(dump_dir, ignore_errors=True) if symbols_dir: shutil.rmtree(symbols_dir, ignore_errors=True) return 0
def WaitForFastbootMode(self, timeout=None, retries=None): """Wait for presentation.device to boot into fastboot mode. This waits for the presentation.device serial to show up in fastboot devices output. """ def fastboot_mode(): return self._serial in self.fastboot.Devices() timeout_retry.WaitFor(fastboot_mode, wait_period=self._FASTBOOT_WAIT_TIME)
def testStartServer(self): # Manually kill off any instances of adb. adb_pids = _hostAdbPids() for p in adb_pids: os.kill(p, signal.SIGKILL) self.assertIsNotNone( timeout_retry.WaitFor( lambda: not _hostAdbPids(), wait_period=0.1, max_tries=10)) # start the adb server start_server_status, _ = cmd_helper.GetCmdStatusAndOutput( [adb_wrapper.AdbWrapper.GetAdbPath(), 'start-server']) # verify that the server is now online self.assertEquals(0, start_server_status) self.assertIsNotNone( timeout_retry.WaitFor( lambda: bool(_hostAdbPids()), wait_period=0.1, max_tries=10))
def RestartServer(): """Restarts the adb server. Raises: CommandFailedError if we fail to kill or restart the server. """ def adb_killed(): return not AdbWrapper.IsServerOnline() def adb_started(): return AdbWrapper.IsServerOnline() AdbWrapper.KillServer() if not timeout_retry.WaitFor(adb_killed, wait_period=1, max_tries=5): # TODO(crbug.com/442319): Switch this to raise an exception if we # figure out why sometimes not all adb servers on bots get killed. logger.warning('Failed to kill adb server') AdbWrapper.StartServer() if not timeout_retry.WaitFor(adb_started, wait_period=1, max_tries=5): raise device_errors.CommandFailedError('Failed to start adb server')
def SetDate(device): def _set_and_verify_date(): if device.build_version_sdk >= version_codes.MARSHMALLOW: date_format = '%m%d%H%M%Y.%S' set_date_command = ['date', '-u'] get_date_command = ['date', '-u'] else: date_format = '%Y%m%d.%H%M%S' set_date_command = ['date', '-s'] get_date_command = ['date'] # TODO(jbudorick): This is wrong on pre-M devices -- get/set are # dealing in local time, but we're setting based on GMT. strgmtime = time.strftime(date_format, time.gmtime()) set_date_command.append(strgmtime) device.RunShellCommand(set_date_command, as_root=True, check_return=True) get_date_command.append('+"%Y%m%d.%H%M%S"') device_time = device.RunShellCommand(get_date_command, check_return=True, as_root=True, single_line=True).replace( '"', '') device_time = datetime.datetime.strptime(device_time, "%Y%m%d.%H%M%S") correct_time = datetime.datetime.strptime(strgmtime, date_format) tdelta = (correct_time - device_time).seconds if tdelta <= 1: logger.info('Date/time successfully set on %s', device) return True else: logger.error('Date mismatch. Device: %s Correct: %s', device_time.isoformat(), correct_time.isoformat()) return False # Sometimes the date is not set correctly on the devices. Retry on failure. if device.IsUserBuild(): # TODO(bpastene): Figure out how to set the date & time on user builds. pass else: if not timeout_retry.WaitFor( _set_and_verify_date, wait_period=1, max_tries=2): raise device_errors.CommandFailedError( 'Failed to set date & time.', device_serial=str(device)) device.EnableRoot() # The following intent can take a bit to complete when ran shortly after # device boot-up. device.BroadcastIntent( intent.Intent(action='android.intent.action.TIME_SET'), timeout=180)
def Start(self, timeout=None): """Start recording video.""" def screenrecord_started(): return bool(self._device.GetPids('screenrecord')) if screenrecord_started(): raise Exception("Can't run multiple concurrent video captures.") self._started.clear() self._recorder_thread = reraiser_thread.ReraiserThread(self._Record) self._recorder_thread.start() timeout_retry.WaitFor( screenrecord_started, wait_period=1, max_tries=timeout) self._started.wait(timeout)
def WaitForUiNode(self, timeout=None, retries=None, **kwargs): """Wait for a node matching a given criteria to appear on the screen. Args: timeout: A number of seconds to wait for the matching node to appear. retries: Number of times to retry in case of adb command errors. For other args, to specify the search criteria, see _UiNode._Find. Returns: The UI node instance found. Raises: device_errors.CommandTimeoutError if the node is not found before the timeout. """ def node_found(): return self.GetUiNode(**kwargs) return timeout_retry.WaitFor(node_found)
def crasher(): def ready_to_crash(): try: return trigger_text == self.device.ReadFile( trigger_file.name, retries=0).strip() except device_errors.CommandFailedError: return False timeout_retry.WaitFor(ready_to_crash, wait_period=2, max_tries=10) if not ready_to_crash(): return False self.device.adb.Shell('echo c > /proc/sysrq-trigger', expect_status=None, timeout=60, retries=0) return True
def EnableBatteryUpdates(self, timeout=None, retries=None): """Restarts device charging so that dumpsys no longer collects power data. Args: timeout: timeout in seconds retries: number of retries Raises: device_errors.DeviceVersionError: If device is not L or higher. """ def battery_updates_enabled(): return (self.GetCharging() or not bool('UPDATES STOPPED' in self._device.RunShellCommand( ['dumpsys', 'battery'], check_return=True))) self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True) timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)
def _ClearPowerData(self): """Resets battery data and makes device appear like it is not charging so that it will collect power data since last charge. Returns: True if power data cleared. False if power data clearing is not supported (pre-L) Raises: device_errors.DeviceVersionError: If power clearing is supported, but fails. """ if self._device.build_version_sdk < version_codes.LOLLIPOP: logger.warning( 'Dumpsys power data only available on 5.0 and above. ' 'Cannot clear power data.') return False self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True) self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True) def test_if_clear(): self._device.RunShellCommand( ['dumpsys', 'batterystats', '--reset'], check_return=True) battery_data = self._device.RunShellCommand( ['dumpsys', 'batterystats', '--charged', '-c'], check_return=True, large_output=True) for line in battery_data: l = line.split(',') if (len(l) > _PWI_POWER_CONSUMPTION_INDEX and l[_ROW_TYPE_INDEX] == 'pwi' and float(l[_PWI_POWER_CONSUMPTION_INDEX]) != 0.0): return False return True try: timeout_retry.WaitFor(test_if_clear, wait_period=1) return True finally: self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True)
def LetCpuCoolToTemperature(self, target_temp, wait_period=30): """Lets device sit to give CPU time to cool down. Implements a similar mechanism to battery_utils.LetBatteryCoolToTemperature Args: temp: A float containing the maximum temperature to allow in degrees c. wait_period: An integer indicating time in seconds to wait between checking. """ target_temp = int(target_temp * self._device_info['temp_multiplier']) def cool_cpu(): # Get the temperatures cpu_temp_paths = self._device_info['cpu_temps'] temps = [] for temp_path in cpu_temp_paths.values(): temp_return = self._device.ReadFile(temp_path) # Output is an array of strings, only need the first line. temps.append(int(temp_return)) if not temps: logger.warning('Unable to read temperature files provided.') return True logger.info('Current CPU temperatures: %s', str(temps)[1:-1]) return all(t <= target_temp for t in temps) logger.info('Waiting for the CPU to cool down to %s', target_temp / self._device_info['temp_multiplier']) # Set the governor to powersave to aid the cooling down of the CPU self._perf_control.SetScalingGovernor('powersave') # Retry 3 times, each time waiting 30 seconds. # This negates most (if not all) of the noise in recorded results without # taking too long timeout_retry.WaitFor(cool_cpu, wait_period=wait_period, max_tries=3) # Set the performance mode self._perf_control.SetHighPerfMode()
def read(self): """Get the object, creating it if necessary.""" if self._initialized.is_set(): return self._val with self._lock: if not self._initialized.is_set(): # We initialize the value on a separate thread to protect # from holding self._lock indefinitely in the event that # self._initializer hangs. initializer_thread = reraiser_thread.ReraiserThread( self._initializer) initializer_thread.start() timeout_retry.WaitFor(lambda: initializer_thread.join(1) or not initializer_thread.isAlive(), wait_period=0) self._val = initializer_thread.GetReturnValue() self._initialized.set() return self._val
def ChargeDeviceToLevel(self, level, wait_period=60): """Enables charging and waits for device to be charged to given level. Args: level: level of charge to wait for. wait_period: time in seconds to wait between checking. """ self.SetCharging(True) def device_charged(): battery_level = self.GetBatteryInfo().get('level') if battery_level is None: logging.warning('Unable to find current battery level.') battery_level = 100 else: logging.info('current battery level: %s', battery_level) battery_level = int(battery_level) return battery_level >= level timeout_retry.WaitFor(device_charged, wait_period=wait_period)
def DisableBatteryUpdates(self, timeout=None, retries=None): """Resets battery data and makes device appear like it is not charging so that it will collect power data since last charge. Args: timeout: timeout in seconds retries: number of retries Raises: device_errors.CommandFailedError: When resetting batterystats fails to reset power values. device_errors.DeviceVersionError: If device is not L or higher. """ def battery_updates_disabled(): return self.GetCharging() is False self._ClearPowerData() self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True) self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True) timeout_retry.WaitFor(battery_updates_disabled, wait_period=1)
def ChargeDeviceToLevel(self, level, wait_period=60): """Enables charging and waits for device to be charged to given level. Args: level: level of charge to wait for. wait_period: time in seconds to wait between checking. Raises: device_errors.DeviceChargingError: If error while charging is detected. """ self.SetCharging(True) charge_status = { 'charge_failure_count': 0, 'last_charge_value': 0 } def device_charged(): battery_level = self.GetBatteryInfo().get('level') if battery_level is None: logger.warning('Unable to find current battery level.') battery_level = 100 else: logger.info('current battery level: %s', battery_level) battery_level = int(battery_level) # Use > so that it will not reset if charge is going down. if battery_level > charge_status['last_charge_value']: charge_status['last_charge_value'] = battery_level charge_status['charge_failure_count'] = 0 else: charge_status['charge_failure_count'] += 1 if (not battery_level >= level and charge_status['charge_failure_count'] >= _MAX_CHARGE_ERROR): raise device_errors.DeviceChargingError( 'Device not charging properly. Current level:%s Previous level:%s' % (battery_level, charge_status['last_charge_value'])) return battery_level >= level timeout_retry.WaitFor(device_charged, wait_period=wait_period)
def FinishProvisioning(device, options): # The lockscreen can't be disabled on user builds, so send a keyevent # to unlock it. if device.IsUserBuild(): device.SendKeyEvent(keyevent.KEYCODE_MENU) if options.min_battery_level is not None: battery = battery_utils.BatteryUtils(device) try: battery.ChargeDeviceToLevel(options.min_battery_level) except device_errors.DeviceChargingError: device.Reboot() battery.ChargeDeviceToLevel(options.min_battery_level) if options.max_battery_temp is not None: try: battery = battery_utils.BatteryUtils(device) battery.LetBatteryCoolToTemperature(options.max_battery_temp) except device_errors.CommandFailedError: logging.exception('Unable to let battery cool to specified temperature.') def _set_and_verify_date(): if device.build_version_sdk >= version_codes.MARSHMALLOW: date_format = '%m%d%H%M%Y.%S' set_date_command = ['date', '-u'] get_date_command = ['date', '-u'] else: date_format = '%Y%m%d.%H%M%S' set_date_command = ['date', '-s'] get_date_command = ['date'] # TODO(jbudorick): This is wrong on pre-M devices -- get/set are # dealing in local time, but we're setting based on GMT. strgmtime = time.strftime(date_format, time.gmtime()) set_date_command.append(strgmtime) device.RunShellCommand(set_date_command, as_root=True, check_return=True) get_date_command.append('+"%Y%m%d.%H%M%S"') device_time = device.RunShellCommand( get_date_command, as_root=True, single_line=True).replace('"', '') device_time = datetime.datetime.strptime(device_time, "%Y%m%d.%H%M%S") correct_time = datetime.datetime.strptime(strgmtime, date_format) tdelta = (correct_time - device_time).seconds if tdelta <= 1: logging.info('Date/time successfully set on %s', device) return True else: logging.error('Date mismatch. Device: %s Correct: %s', device_time.isoformat(), correct_time.isoformat()) return False if options.disable_selinux: device.RunShellCommand("su -c setenforce 0", as_root=True) if options.force_battery_status: device.RunShellCommand("dumpsys battery set status 5", as_root=True) device.RunShellCommand("dumpsys battery set level 100", as_root=True) if options.disable_predictive_keyboard: DisablePredictiveKeyboard(device) # Sometimes the date is not set correctly on the devices. Retry on failure. if device.IsUserBuild(): # TODO(bpastene): Figure out how to set the date & time on user builds. pass else: # FIXME: Some samsung devices can not set the date and time. so we skip this. if False and not timeout_retry.WaitFor(_set_and_verify_date, wait_period=1, max_tries=2): raise device_errors.CommandFailedError( 'Failed to set date & time.', device_serial=str(device)) props = device.RunShellCommand('getprop', check_return=True) for prop in props: logging.info(' %s', prop) if options.auto_reconnect: _PushAndLaunchAdbReboot(device, options.target)
correct_time = datetime.datetime.strptime(strgmtime, date_format) tdelta = (correct_time - device_time).seconds if tdelta <= 1: logger.info('Date/time successfully set on %s', presentation.device) return True else: logger.error('Date mismatch. Device: %s Correct: %s', device_time.isoformat(), correct_time.isoformat()) return False # Sometimes the date is not set correctly on the devices. Retry on failure. if presentation.device.IsUserBuild(): # TODO(bpastene): Figure out how to set the date & time on user builds. pass else: if not timeout_retry.WaitFor( _set_and_verify_date, wait_period=1, max_tries=2): raise device_errors.CommandFailedError( 'Failed to set date & time.', device_serial=str(presentation.device)) presentation.device.EnableRoot() presentation.device.BroadcastIntent( intent.Intent(action='android.intent.action.TIME_SET')) def LogDeviceProperties(presentation.device): props = presentation.device.RunShellCommand(['getprop'], check_return=True) for prop in props: logger.info(' %s', prop) def CheckExternalStorage(presentation.device): """Checks that storage is writable and if not makes it writable.
def _FindDeviceWithTimeout(self): """Find which device to use with timeout.""" timeout_retry.WaitFor(self._FindDevice, wait_period=1)
def main(): parser = CommandParser() args, extra_cmd_args = parser.parse_known_args(sys.argv[1:]) logging.basicConfig(level=logging.INFO) if args.target: test_cmd = [os.path.join('bin', 'run_%s' % args.target), '-v'] test_cmd += extra_cmd_args elif args.script: test_cmd = [args.script] test_cmd += extra_cmd_args else: test_cmd = extra_cmd_args test_env = dict(os.environ) logdog_cmd = [] with tempfile_ext.NamedTemporaryDirectory( prefix='tmp_android_logdog_wrapper') as temp_directory: if not os.path.exists(args.logdog_bin_cmd): logging.error( 'Logdog binary %s unavailable. Unable to create logdog client', args.logdog_bin_cmd) else: streamserver_uri = 'unix:%s' % os.path.join( temp_directory, 'butler.sock') prefix = os.path.join('android', 'swarming', 'logcats', os.environ.get('SWARMING_TASK_ID')) logdog_cmd = [ args.logdog_bin_cmd, '-project', PROJECT, '-output', OUTPUT, '-prefix', prefix, '--service-account-json', SERVICE_ACCOUNT_JSON, '-coordinator-host', COORDINATOR_HOST, 'serve', '-streamserver-uri', streamserver_uri ] test_env.update({ 'LOGDOG_STREAM_PROJECT': PROJECT, 'LOGDOG_STREAM_PREFIX': prefix, 'LOGDOG_STREAM_SERVER_PATH': streamserver_uri, 'LOGDOG_COORDINATOR_HOST': COORDINATOR_HOST, }) logdog_proc = None if logdog_cmd: logdog_proc = subprocess.Popen(logdog_cmd) with NoLeakingProcesses(logdog_proc): with NoLeakingProcesses(subprocess.Popen( test_cmd, env=test_env)) as test_proc: with signal_handler.SignalHandler( signal.SIGTERM, CreateStopTestsMethod(test_proc)): result = test_proc.wait() if logdog_proc: def logdog_stopped(): return logdog_proc.poll() is not None logdog_proc.terminate() timeout_retry.WaitFor( logdog_stopped, wait_period=1, max_tries=LOGDOG_TERMINATION_TIMEOUT) # If logdog_proc hasn't finished by this point, allow # NoLeakingProcesses to kill it. return result