def InstallCommands(device): if device.IsUserBuild(): raise device_errors.CommandFailedError( 'chromium_commands currently requires a userdebug build.', device_serial=device.adb.GetDeviceSerial()) chromium_commands_jar_path = devil_env.config.FetchPath('chromium_commands') if not os.path.exists(chromium_commands_jar_path): raise device_errors.CommandFailedError( '%s not found. Please build chromium_commands.' % chromium_commands_jar_path) device.RunShellCommand( ['mkdir', '-p', BIN_DIR, _FRAMEWORK_DIR], check_return=True) for command, main_class in _COMMANDS.iteritems(): shell_command = _SHELL_COMMAND_FORMAT % ( file_system.TEST_EXECUTABLE_DIR, main_class) shell_file = '%s/%s' % (BIN_DIR, command) device.WriteFile(shell_file, shell_command) device.RunShellCommand( ['chmod', '755', shell_file], check_return=True) device.adb.Push( chromium_commands_jar_path, '%s/chromium_commands.jar' % _FRAMEWORK_DIR)
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 EnableSystemAppModification(device): """A context manager that allows system apps to be modified while in scope. Args: device: (device_utils.DeviceUtils) the device """ if device.GetProp(_ENABLE_MODIFICATION_PROP) == '1': yield return device.EnableRoot() if not device.HasRoot(): raise device_errors.CommandFailedError( 'Failed to enable modification of system apps on non-rooted device', str(device)) try: # Disable Marshmallow's Verity security feature if device.build_version_sdk >= version_codes.MARSHMALLOW: logger.info('Disabling Verity on %s', device.serial) device.adb.DisableVerity() device.Reboot() device.WaitUntilFullyBooted() device.EnableRoot() device.adb.Remount() device.RunShellCommand(['stop'], check_return=True) device.SetProp(_ENABLE_MODIFICATION_PROP, '1') yield finally: device.SetProp(_ENABLE_MODIFICATION_PROP, '0') device.Reboot() device.WaitUntilFullyBooted()
def Commit(self): """Save the current set of preferences to the device. Only actually saves if some preferences have been modified. """ if not self.changed: return self._device.RunShellCommand( ['mkdir', '-p', posixpath.dirname(self.path)], as_root=True, check_return=True) self._device.WriteFile(self.path, str(self), as_root=True) # Creating the directory/file can cause issues with SELinux if they did # not already exist. As a workaround, apply the package's security context # to the shared_prefs directory, which mimics the behavior of a file # created by the app itself if self._device.build_version_sdk >= version_codes.MARSHMALLOW: security_context = self._GetSecurityContext(self.package) if security_context == None: raise device_errors.CommandFailedError( 'Failed to get security context for %s' % self.package) self._device.RunShellCommand([ 'chcon', '-R', security_context, '/data/data/%s/shared_prefs' % self.package ], as_root=True, check_return=True) self._device.KillAll(self.package, exact=True, as_root=True, quiet=True) self._changed = False
def _TearDownSystemAppModification(device, should_restore_root, timeout=None, retries=None): try: # The function may be re-entered after the the device loses root # privilege. For instance if the adb server is restarted before # re-entering the function then the device may lose root privilege. # Therefore we need to do a sanity check for root privilege # on the device and then re-enable root privilege if the device # does not have it. if not device.HasRoot(): logger.warning('Need to re-enable root.') device.EnableRoot() if not device.HasRoot(): raise device_errors.CommandFailedError( ('Failed to tear down modification of ' 'system apps on non-rooted device.'), str(device)) device.SetProp(_ENABLE_MODIFICATION_PROP, '0') device.Reboot() device.WaitUntilFullyBooted() if should_restore_root: device.EnableRoot() except device_errors.CommandTimeoutError: logger.error('Timed out while tearing down system app modification.') logger.error(' device state: %s', device.adb.GetState()) raise
def _GetTests(self): if self._test_instance.extract_test_list_from_filter: # When the exact list of tests to run is given via command-line (e.g. when # locally iterating on a specific test), skip querying the device (which # takes ~3 seconds). tests = _ExtractTestsFromFilter(self._test_instance.gtest_filter) if tests: return tests # Even when there's only one device, it still makes sense to retrieve the # test list so that tests can be split up and run in batches rather than all # at once (since test output is not streamed). @local_device_test_run.handle_shard_failures_with( on_failure=self._env.BlacklistDevice) def list_tests(dev): tests = self._delegate.Run(None, dev, flags='--gtest_list_tests', timeout=30) tests = gtest_test_instance.ParseGTestListTests(tests) tests = self._test_instance.FilterTests(tests) return tests # Query all devices in case one fails. test_lists = self._env.parallel_devices.pMap(list_tests).pGet(None) # If all devices failed to list tests, raise an exception. # Check that tl is not None and is not empty. if all(not tl for tl in test_lists): raise device_errors.CommandFailedError( 'Failed to list tests on any device') return list(sorted(set().union(*[set(tl) for tl in test_lists if tl])))
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 CheckWebViewIsUninstalled(device): """Throws if WebView is still installed.""" for webview_package in WEBVIEW_PACKAGES: if device.IsApplicationInstalled(webview_package): raise device_errors.CommandFailedError( '{} is still installed on the device'.format(webview_package), device)
def RemoveSystemApps(device, system_app_remove_list, system_package_remove_list): """Attempts to remove the provided system apps from the given device. Arguments: device: The device to remove the system apps from. system_app_remove_list: A list of app names to remove, e.g. ['WebViewGoogle', 'GoogleVrCore'] system_package_remove_list: A list of app packages to remove, e.g. ['com.google.android.webview'] """ device.EnableRoot() if device.HasRoot(): system_app_paths = ( _FindSystemAppPaths(device, system_app_remove_list) + _FindSystemPackagePaths(device, system_package_remove_list)) if system_app_paths: # Disable Marshmallow's Verity security feature if device.build_version_sdk >= version_codes.MARSHMALLOW: logger.info('Disabling Verity on %s', device.serial) device.adb.DisableVerity() device.Reboot() device.WaitUntilFullyBooted() device.EnableRoot() device.adb.Remount() device.RunShellCommand(['stop'], check_return=True) device.RemovePath(system_app_paths, force=True, recursive=True) device.RunShellCommand(['start'], check_return=True) else: raise device_errors.CommandFailedError( 'Failed to remove system apps from non-rooted device', str(device))
def GetPowerData(self, timeout=None, retries=None): """Get power data for device. Args: timeout: timeout in seconds retries: number of retries Returns: Dict containing system power, and a per-package power dict keyed on package names. { 'system_total': 23.1, 'per_package' : { package_name: { 'uid': uid, 'data': [1,2,3] }, } } """ if 'uids' not in self._cache: self._cache['uids'] = {} dumpsys_output = self._device.RunShellCommand( ['dumpsys', 'batterystats', '-c'], check_return=True, large_output=True) csvreader = csv.reader(dumpsys_output) pwi_entries = collections.defaultdict(list) system_total = None for entry in csvreader: if entry[_DUMP_VERSION_INDEX] not in ['8', '9']: # Wrong dumpsys version. raise device_errors.DeviceVersionError( 'Dumpsys version must be 8 or 9. "%s" found.' % entry[_DUMP_VERSION_INDEX]) if _ROW_TYPE_INDEX < len(entry) and entry[_ROW_TYPE_INDEX] == 'uid': current_package = entry[_PACKAGE_NAME_INDEX] if (self._cache['uids'].get(current_package) and self._cache['uids'].get(current_package) != entry[_PACKAGE_UID_INDEX]): raise device_errors.CommandFailedError( 'Package %s found multiple times with different UIDs %s and %s' % (current_package, self._cache['uids'][current_package], entry[_PACKAGE_UID_INDEX])) self._cache['uids'][current_package] = entry[_PACKAGE_UID_INDEX] elif (_PWI_POWER_CONSUMPTION_INDEX < len(entry) and entry[_ROW_TYPE_INDEX] == 'pwi' and entry[_PWI_AGGREGATION_INDEX] == 'l'): pwi_entries[entry[_PWI_UID_INDEX]].append( float(entry[_PWI_POWER_CONSUMPTION_INDEX])) elif (_PWS_POWER_CONSUMPTION_INDEX < len(entry) and entry[_ROW_TYPE_INDEX] == 'pws' and entry[_PWS_AGGREGATION_INDEX] == 'l'): # This entry should only appear once. assert system_total is None system_total = float(entry[_PWS_POWER_CONSUMPTION_INDEX]) per_package = {p: {'uid': uid, 'data': pwi_entries[uid]} for p, uid in self._cache['uids'].iteritems()} return {'system_total': system_total, 'per_package': per_package}
def CheckWebViewIsUninstalled(device): """Throws if WebView is still installed.""" for webview_package in WEBVIEW_PACKAGES: paths = device.GetApplicationPaths(webview_package) if paths: raise device_errors.CommandFailedError( '{} is still installed on the device at {}'.format( webview_package, paths), device)
def _GetTests(self): if self._test_instance.extract_test_list_from_filter: # When the exact list of tests to run is given via command-line (e.g. when # locally iterating on a specific test), skip querying the device (which # takes ~3 seconds). tests = _ExtractTestsFromFilter(self._test_instance.gtest_filter) if tests: return tests # Even when there's only one device, it still makes sense to retrieve the # test list so that tests can be split up and run in batches rather than all # at once (since test output is not streamed). @local_device_environment.handle_shard_failures_with( on_failure=self._env.BlacklistDevice) def list_tests(dev): timeout = 30 retries = 1 if self._test_instance.wait_for_java_debugger: timeout = None # TODO(crbug.com/726880): Remove retries when no longer necessary. for i in range(0, retries + 1): raw_test_list = crash_handler.RetryOnSystemCrash( lambda d: self._delegate.Run( None, d, flags='--gtest_list_tests', timeout=timeout), device=dev) tests = gtest_test_instance.ParseGTestListTests(raw_test_list) if not tests: logging.info('No tests found. Output:') for l in raw_test_list: logging.info(' %s', l) logging.info('Logcat:') for line in dev.adb.Logcat(dump=True): logging.info(line) dev.adb.Logcat(clear=True) if i < retries: logging.info('Retrying...') else: break return tests # Query all devices in case one fails. test_lists = self._env.parallel_devices.pMap(list_tests).pGet(None) # If all devices failed to list tests, raise an exception. # Check that tl is not None and is not empty. if all(not tl for tl in test_lists): raise device_errors.CommandFailedError( 'Failed to list tests on any device') tests = list(sorted(set().union(*[set(tl) for tl in test_lists if tl]))) tests = self._test_instance.FilterTests(tests) tests = self._ApplyExternalSharding( tests, self._test_instance.external_shard_index, self._test_instance.total_external_shards) return tests
def CheckBuildTypeSupportsFlags(device, command_line_flags_file): is_webview = command_line_flags_file == 'webview-command-line' if device.IsUserBuild() and is_webview: raise device_errors.CommandFailedError( 'WebView only respects flags on a userdebug or eng device, yours ' 'is a user build.', device) elif device.IsUserBuild(): logging.warning( 'Your device (%s) is a user build; Chrome may or may not pick up ' 'your commandline flags. Check your ' '"command_line_on_non_rooted_enabled" preference, or switch ' 'devices.', device)
def _GetTestsFromRunner(self): test_apk_path = self._test_instance.test_apk.path pickle_path = '%s-runner.pickle' % test_apk_path try: return instrumentation_test_instance.GetTestsFromPickle( pickle_path, test_apk_path) except instrumentation_test_instance.TestListPickleException as e: logging.info('Could not get tests from pickle: %s', e) logging.info('Getting tests by having %s list them.', self._test_instance.junit4_runner_class) def list_tests(d): def _run(dev): with device_temp_file.DeviceTempFile( dev.adb, suffix='.json', dir=dev. GetExternalStoragePath()) as dev_test_list_json: junit4_runner_class = self._test_instance.junit4_runner_class test_package = self._test_instance.test_package extras = {} extras['log'] = 'true' extras[_EXTRA_TEST_LIST] = dev_test_list_json.name target = '%s/%s' % (test_package, junit4_runner_class) kwargs = {} if self._test_instance.wait_for_java_debugger: kwargs['timeout'] = None test_list_run_output = dev.StartInstrumentation( target, extras=extras, retries=0, **kwargs) if any(test_list_run_output): logging.error('Unexpected output while listing tests:') for line in test_list_run_output: logging.error(' %s', line) with tempfile_ext.NamedTemporaryDirectory() as host_dir: host_file = os.path.join(host_dir, 'list_tests.json') dev.PullFile(dev_test_list_json.name, host_file) with open(host_file, 'r') as host_file: return json.load(host_file) return crash_handler.RetryOnSystemCrash(_run, d) raw_test_lists = self._env.parallel_devices.pMap(list_tests).pGet(None) # If all devices failed to list tests, raise an exception. # Check that tl is not None and is not empty. if all(not tl for tl in raw_test_lists): raise device_errors.CommandFailedError( 'Failed to list tests on any device') # Get the first viable list of raw tests raw_tests = [tl for tl in raw_test_lists if tl][0] instrumentation_test_instance.SaveTestsToPickle( pickle_path, test_apk_path, raw_tests) return raw_tests
def EnableSystemAppModification(device): """A context manager that allows system apps to be modified while in scope. Args: device: (device_utils.DeviceUtils) the device """ if device.GetProp(_ENABLE_MODIFICATION_PROP) == '1': yield return # All calls that could potentially need root should run with as_root=True, but # it looks like some parts of Telemetry work as-is by implicitly assuming that # root is already granted if it's necessary. The reboot can mess with this, so # as a workaround, check whether we're starting with root already, and if so, # restore the device to that state at the end. should_restore_root = device.HasRoot() device.EnableRoot() if not device.HasRoot(): raise device_errors.CommandFailedError( 'Failed to enable modification of system apps on non-rooted device', str(device)) try: # Disable Marshmallow's Verity security feature if device.build_version_sdk >= version_codes.MARSHMALLOW: logger.info('Disabling Verity on %s', device.serial) device.adb.DisableVerity() device.Reboot() device.WaitUntilFullyBooted() device.EnableRoot() device.adb.Remount() device.RunShellCommand(['stop'], check_return=True) device.SetProp(_ENABLE_MODIFICATION_PROP, '1') yield except device_errors.CommandFailedError as e: if device.adb.is_emulator: # Point the user to documentation, since there's a good chance they can # workaround this on an emulator. docs_url = ( 'https://chromium.googlesource.com/chromium/src/+/' 'master/docs/android_emulator.md#writable-system-partition') logger.error( 'Did you start the emulator with "-writable-system?"\n' 'See %s\n', docs_url) raise e finally: device.SetProp(_ENABLE_MODIFICATION_PROP, '0') device.Reboot() device.WaitUntilFullyBooted() if should_restore_root: device.EnableRoot()
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 InstallCommands(device): if device.IsUserBuild(): raise device_errors.CommandFailedError( 'chromium_commands currently requires a userdebug build.', device_serial=device.adb.GetDeviceSerial()) chromium_commands_jar_path = os.path.join(constants.GetOutDirectory(), constants.SDK_BUILD_JAVALIB_DIR, 'chromium_commands.dex.jar') if not os.path.exists(chromium_commands_jar_path): raise device_errors.CommandFailedError( '%s not found. Please build chromium_commands.' % chromium_commands_jar_path) device.RunShellCommand(['mkdir', BIN_DIR, _FRAMEWORK_DIR]) for command, main_class in _COMMANDS.iteritems(): shell_command = _SHELL_COMMAND_FORMAT % (constants.TEST_EXECUTABLE_DIR, main_class) shell_file = '%s/%s' % (BIN_DIR, command) device.WriteFile(shell_file, shell_command) device.RunShellCommand(['chmod', '755', shell_file], check_return=True) device.adb.Push(chromium_commands_jar_path, '%s/chromium_commands.jar' % _FRAMEWORK_DIR)
def Commit(self, force_commit=False): """Save the current set of preferences to the device. Only actually saves if some preferences have been modified or force_commit is set to True. Args: force_commit: Commit even if no changes have been made to the SharedPrefs instance. """ if not (self.changed or force_commit): return self._device.RunShellCommand( ['mkdir', '-p', posixpath.dirname(self.path)], as_root=True, check_return=True) self._device.WriteFile(self.path, str(self), as_root=True) # Creating the directory/file can cause issues with SELinux if they did # not already exist. As a workaround, apply the package's security context # to the shared_prefs directory, which mimics the behavior of a file # created by the app itself if self._device.build_version_sdk >= version_codes.MARSHMALLOW: security_context = self._device.GetSecurityContextForPackage( self.package, encrypted=self._encrypted) if security_context is None: raise device_errors.CommandFailedError( 'Failed to get security context for %s' % self.package) paths = [posixpath.dirname(self.path), self.path] self._device.ChangeSecurityContext(security_context, paths) # Ensure that there isn't both an encrypted and unencrypted version of the # file on the device at the same time. if self._device.build_version_sdk >= version_codes.NOUGAT: remove_path = (self._unencrypted_path if self._encrypted else self._encrypted_path) if self._device.PathExists(remove_path, as_root=True): logging.warning( 'Found an equivalent shared prefs file at %s, removing', remove_path) self._device.RemovePath(remove_path, as_root=True) self._device.KillAll(self.package, exact=True, as_root=True, quiet=True) self._changed = False
def update_flags(device): if device.IsUserBuild() and is_webview: raise device_errors.CommandFailedError( 'WebView only respects flags on a userdebug or eng device, yours ' 'is a user build.', device) elif device.IsUserBuild(): logging.warning( 'Your device (%s) is a user build; Chrome may or may not pick up ' 'your commandline flags. Check your ' '"command_line_on_non_rooted_enabled" preference, or switch ' 'devices.', device) changer = flag_changer.FlagChanger(device, args.name) if remote_args is not None: flags = changer.ReplaceFlags(remote_args) else: flags = changer.GetCurrentFlags() return (device, device.build_description, flags)
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: logging.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) reset_output = self._device.RunShellCommand( ['dumpsys', 'batterystats', '--reset'], check_return=True) logging.info('Output from resetting batterystats:') for l in reset_output: logging.info(' %s', l) 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 l[_PWI_POWER_CONSUMPTION_INDEX] != 0): self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True) raise device_errors.CommandFailedError( 'Non-zero pmi value found after reset: "%s"' % line) self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True) return True
def _SetUpSystemAppModification(device, timeout=None, retries=None): # Ensure that the device is online & available before proceeding to # handle the case where something fails in the middle of set up and # triggers a retry. device.WaitUntilFullyBooted() # All calls that could potentially need root should run with as_root=True, but # it looks like some parts of Telemetry work as-is by implicitly assuming that # root is already granted if it's necessary. The reboot can mess with this, so # as a workaround, check whether we're starting with root already, and if so, # restore the device to that state at the end. should_restore_root = device.HasRoot() device.EnableRoot() if not device.HasRoot(): raise device_errors.CommandFailedError( 'Failed to enable modification of system apps on non-rooted device', str(device)) try: # Disable Marshmallow's Verity security feature if device.build_version_sdk >= version_codes.MARSHMALLOW: logger.info('Disabling Verity on %s', device.serial) device.adb.DisableVerity() device.Reboot() device.WaitUntilFullyBooted() device.EnableRoot() device.adb.Remount() device.RunShellCommand(['stop'], check_return=True) device.SetProp(_ENABLE_MODIFICATION_PROP, '1') except device_errors.CommandFailedError: if device.adb.is_emulator: # Point the user to documentation, since there's a good chance they can # workaround this on an emulator. docs_url = ( 'https://chromium.googlesource.com/chromium/src/+/' 'HEAD/docs/android_emulator.md#writable-system-partition') logger.error( 'Did you start the emulator with "-writable-system?"\n' 'See %s\n', docs_url) raise return should_restore_root
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 EnableSystemAppModification(device): """A context manager that allows system apps to be modified while in scope. Args: device: (device_utils.DeviceUtils) the device """ if device.GetProp(_ENABLE_MODIFICATION_PROP) == '1': yield return # All calls that could potentially need root should run with as_root=True, but # it looks like some parts of Telemetry work as-is by implicitly assuming that # root is already granted if it's necessary. The reboot can mess with this, so # as a workaround, check whether we're starting with root already, and if so, # restore the device to that state at the end. should_restore_root = device.HasRoot() device.EnableRoot() if not device.HasRoot(): raise device_errors.CommandFailedError( 'Failed to enable modification of system apps on non-rooted device', str(device)) try: # Disable Marshmallow's Verity security feature if device.build_version_sdk >= version_codes.MARSHMALLOW: logger.info('Disabling Verity on %s', device.serial) device.adb.DisableVerity() device.Reboot() device.WaitUntilFullyBooted() device.EnableRoot() device.adb.Remount() device.RunShellCommand(['stop'], check_return=True) device.SetProp(_ENABLE_MODIFICATION_PROP, '1') yield finally: device.SetProp(_ENABLE_MODIFICATION_PROP, '0') device.Reboot() device.WaitUntilFullyBooted() if should_restore_root: device.EnableRoot()
def GetFuelGaugeChargeCounter(self, timeout=None, retries=None): """Get value of charge_counter on fuel gauge chip. Device must have charging disabled for this, not just battery updates disabled. The only device that this currently works with is the nexus 5. Args: timeout: timeout in seconds retries: number of retries Returns: value of charge_counter for fuel gauge chip in units of nAh. Raises: device_errors.CommandFailedError: If fuel gauge chip not found. """ if self.SupportsFuelGauge(): return int( self._device.ReadFile( self._cache['profile']['charge_counter'])) raise device_errors.CommandFailedError('Unable to find fuel gauge.')
def _FlashPartitions(self, partitions, directory, wipe=False, force=False): """Flashes all given partiitons with all given images. Args: partitions: List of partitions to flash. directory: Directory where all partitions can be found. wipe: If set to true, will automatically detect if cache and userdata partitions are sent, and if so ignore them. force: boolean to decide to ignore board name safety checks. Raises: device_errors.CommandFailedError(): If image cannot be found or if bad partition name is give. """ if not self._VerifyBoard(directory): if force: logger.warning( 'Could not verify build is meant to be installed on ' 'the current device type, but force flag is set. ' 'Flashing device. Possibly dangerous operation.') else: raise device_errors.CommandFailedError( 'Could not verify build is meant to be installed on the current ' 'device type. Run again with force=True to force flashing with an ' 'unverified board.') flash_image_files = _FindAndVerifyPartitionsAndImages( partitions, directory) partitions = flash_image_files.keys() for partition in partitions: if _KNOWN_PARTITIONS[partition].get('wipe_only') and not wipe: logger.info( 'Not flashing in wipe mode. Skipping partition %s.', partition) else: logger.info('Flashing %s with %s', partition, flash_image_files[partition]) self.fastboot.Flash(partition, flash_image_files[partition]) if _KNOWN_PARTITIONS[partition].get('restart', False): self.Reboot(bootloader=True)
def alwaysRaisesCommandFailedError(timeout=None, retries=None): DecoratorsTest._decorated_function_called_count += 1 raise device_errors.CommandFailedError('testCommand failed')
def _GetTestsFromRunner(self): test_apk_path = self._test_instance.test_apk.path pickle_path = '%s-runner.pickle' % test_apk_path # For incremental APKs, the code doesn't live in the apk, so instead check # the timestamp of the target's .stamp file. if self._test_instance.test_apk_incremental_install_json: with open(self._test_instance.test_apk_incremental_install_json ) as f: data = json.load(f) out_dir = constants.GetOutDirectory() test_mtime = max( os.path.getmtime(os.path.join(out_dir, p)) for p in data['dex_files']) else: test_mtime = os.path.getmtime(test_apk_path) try: return instrumentation_test_instance.GetTestsFromPickle( pickle_path, test_mtime) except instrumentation_test_instance.TestListPickleException as e: logging.info('Could not get tests from pickle: %s', e) logging.info('Getting tests by having %s list them.', self._test_instance.junit4_runner_class) def list_tests(d): def _run(dev): with device_temp_file.DeviceTempFile( dev.adb, suffix='.json', dir=dev. GetExternalStoragePath()) as dev_test_list_json: junit4_runner_class = self._test_instance.junit4_runner_class test_package = self._test_instance.test_package extras = { 'log': 'true', # Workaround for https://github.com/mockito/mockito/issues/922 'notPackage': 'net.bytebuddy', } extras[_EXTRA_TEST_LIST] = dev_test_list_json.name target = '%s/%s' % (test_package, junit4_runner_class) timeout = 120 if self._test_instance.wait_for_java_debugger: timeout = None test_list_run_output = dev.StartInstrumentation( target, extras=extras, retries=0, timeout=timeout) if any(test_list_run_output): logging.error('Unexpected output while listing tests:') for line in test_list_run_output: logging.error(' %s', line) with tempfile_ext.NamedTemporaryDirectory() as host_dir: host_file = os.path.join(host_dir, 'list_tests.json') dev.PullFile(dev_test_list_json.name, host_file) with open(host_file, 'r') as host_file: return json.load(host_file) return crash_handler.RetryOnSystemCrash(_run, d) raw_test_lists = self._env.parallel_devices.pMap(list_tests).pGet(None) # If all devices failed to list tests, raise an exception. # Check that tl is not None and is not empty. if all(not tl for tl in raw_test_lists): raise device_errors.CommandFailedError( 'Failed to list tests on any device') # Get the first viable list of raw tests raw_tests = [tl for tl in raw_test_lists if tl][0] instrumentation_test_instance.SaveTestsToPickle(pickle_path, raw_tests) return raw_tests
base=%s export CLASSPATH=$base/framework/chromium_commands.jar exec app_process $base/bin %s $@ """) def Installed(presentation.device): paths = [posixpath.join(BIN_DIR, c) for c in _COMMANDS] paths.append(posixpath.join(_FRAMEWORK_DIR, 'chromium_commands.jar')) return presentation.device.PathExists(paths) def InstallCommands(presentation.device): if presentation.device.IsUserBuild(): raise device_errors.CommandFailedError( 'chromium_commands currently requires a userdebug build.', device_serial=presentation.device.adb.GetDeviceSerial()) chromium_commands_jar_path = devil_env.config.FetchPath('chromium_commands') if not os.path.exists(chromium_commands_jar_path): raise device_errors.CommandFailedError( '%s not found. Please build chromium_commands.' % chromium_commands_jar_path) presentation.device.RunShellCommand( ['mkdir', '-p', BIN_DIR, _FRAMEWORK_DIR], check_return=True) for command, main_class in _COMMANDS.iteritems(): shell_command = _SHELL_COMMAND_FORMAT % ( file_system.TEST_EXECUTABLE_DIR, main_class) shell_file = '%s/%s' % (BIN_DIR, command) presentation.device.WriteFile(shell_file, shell_command)
def alwaysRaisesCommandFailedError(timeout=None, retries=None): actual_tries[0] += 1 raise device_errors.CommandFailedError('Command failed :(')
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)