def __init__(self, host, port_name='', apk='', product='', options=None, **kwargs): super(AndroidPort, self).__init__(host, port_name, options=options, **kwargs) self._operating_system = 'android' self._version = 'kitkat' fs = host.filesystem self._local_port = factory.PortFactory(host).get(**kwargs) if apk or product: self._driver_details = DriverDetails(apk) browser_type = fs.splitext(fs.basename(apk))[0].lower() self._browser_type = _friendly_browser_names.get( browser_type, browser_type) self._wpt_product_arg = product else: # The legacy test runner will be used to run web tests on Android. # So we need to initialize several port member variables. _import_android_packages_if_necessary() self._driver_details = ContentShellDriverDetails() self._browser_type = 'content_shell' self._debug_logging = self.get_option('android_logging') self.server_process_constructor = self._android_server_process_constructor self._wpt_product_arg = '' if not self.get_option('disable_breakpad'): self._dump_reader = DumpReaderAndroid(host, self._build_path()) # Initialize the AndroidDevices class which tracks available devices. default_devices = None if hasattr(self._options, 'adb_devices') and len( self._options.adb_devices): default_devices = self._options.adb_devices self._devices = AndroidDevices(default_devices, self._debug_logging) devil_chromium.Initialize(output_directory=self._build_path(), adb_path=self._path_from_chromium_base( 'third_party', 'android_sdk', 'public', 'platform-tools', 'adb')) devil_env.config.InitializeLogging( logging.DEBUG if self._debug_logging and self.get_option('debug_rwt_logging') else logging.WARNING) prepared_devices = self.get_option('prepared_devices', []) for serial in prepared_devices: self._devices.set_device_prepared(serial)
def __init__(self, host, port_name, **kwargs): _import_android_packages_if_necessary() super(AndroidPort, self).__init__(host, port_name, **kwargs) self._operating_system = 'android' self._version = 'kitkat' self._host_port = factory.PortFactory(host).get(**kwargs) self.server_process_constructor = self._android_server_process_constructor if not self.get_option('disable_breakpad'): self._dump_reader = DumpReaderAndroid(host, self._build_path()) if self.driver_name() != self.CONTENT_SHELL_NAME: raise AssertionError( 'Web tests on Android only support content_shell as the driver.' ) self._driver_details = ContentShellDriverDetails() # Initialize the AndroidDevices class which tracks available devices. default_devices = None if hasattr(self._options, 'adb_devices') and len( self._options.adb_devices): default_devices = self._options.adb_devices self._debug_logging = self.get_option('android_logging') self._devices = AndroidDevices(default_devices, self._debug_logging) devil_chromium.Initialize(output_directory=self._build_path(), adb_path=self._path_from_chromium_base( 'third_party', 'android_tools', 'sdk', 'platform-tools', 'adb')) devil_env.config.InitializeLogging( logging.DEBUG if self._debug_logging and self.get_option('debug_rwt_logging') else logging.WARNING) prepared_devices = self.get_option('prepared_devices', []) for serial in prepared_devices: self._devices.set_device_prepared(serial)
class AndroidPort(base.Port): port_name = 'android' # Avoid initializing the adb path [worker count]+1 times by storing it as a static member. _adb_path = None SUPPORTED_VERSIONS = ('android') FALLBACK_PATHS = { 'kitkat': ['android'] + linux.LinuxPort.latest_platform_fallback_path() } BUILD_REQUIREMENTS_URL = 'https://www.chromium.org/developers/how-tos/android-build-instructions' def __init__(self, host, port_name, **kwargs): _import_android_packages_if_necessary() super(AndroidPort, self).__init__(host, port_name, **kwargs) self._operating_system = 'android' self._version = 'kitkat' self._host_port = factory.PortFactory(host).get(**kwargs) self.server_process_constructor = self._android_server_process_constructor if not self.get_option('disable_breakpad'): self._dump_reader = DumpReaderAndroid(host, self._build_path()) if self.driver_name() != self.CONTENT_SHELL_NAME: raise AssertionError( 'Web tests on Android only support content_shell as the driver.' ) self._driver_details = ContentShellDriverDetails() # Initialize the AndroidDevices class which tracks available devices. default_devices = None if hasattr(self._options, 'adb_devices') and len( self._options.adb_devices): default_devices = self._options.adb_devices self._debug_logging = self.get_option('android_logging') self._devices = AndroidDevices(default_devices, self._debug_logging) devil_chromium.Initialize(output_directory=self._build_path(), adb_path=self._path_from_chromium_base( 'third_party', 'android_tools', 'sdk', 'platform-tools', 'adb')) devil_env.config.InitializeLogging( logging.DEBUG if self._debug_logging and self.get_option('debug_rwt_logging') else logging.WARNING) prepared_devices = self.get_option('prepared_devices', []) for serial in prepared_devices: self._devices.set_device_prepared(serial) def default_smoke_test_only(self): return True def additional_driver_flags(self): return super(AndroidPort, self).additional_driver_flags() + \ self._driver_details.additional_command_line_flags(use_breakpad=not self.get_option('disable_breakpad')) def default_timeout_ms(self): # Android platform has less computing power than desktop platforms. # Using 10 seconds allows us to pass most slow tests which are not # marked as slow tests on desktop platforms. return 10 * 1000 def driver_stop_timeout(self): # The driver doesn't respond to closing stdin, so we might as well stop the driver immediately. return 0.0 def default_child_processes(self): usable_devices = self._devices.usable_devices(self._executive) if not usable_devices: raise test_run_results.TestRunException( exit_codes.NO_DEVICES_EXIT_STATUS, 'Unable to find any attached Android devices.') return len(usable_devices) def max_drivers_per_process(self): # Android falls over when we try to run multiple content_shells per worker. # See https://codereview.chromium.org/1158323009/ return 1 def check_build(self, needs_http, printer): exit_status = super(AndroidPort, self).check_build(needs_http, printer) if exit_status: return exit_status return self._check_devices(printer) def _check_devices(self, printer): # Push the executables and other files to the devices; doing this now # means we can do this in parallel in the manager process and not mix # this in with starting and stopping workers. lock = threading.Lock() def log_safely(msg, throttled=True): if throttled: callback = printer.write_throttled_update else: callback = printer.write_update with lock: callback('%s' % msg) def _setup_device_impl(device): log_safely('preparing device', throttled=False) if self._devices.is_device_prepared(device.serial): return device.EnableRoot() perf_control.PerfControl(device).SetPerfProfilingMode() # Required by webkit_support::GetWebKitRootDirFilePath(). # Other directories will be created automatically by adb push. device.RunShellCommand( ['mkdir', '-p', DEVICE_SOURCE_ROOT_DIR + 'chrome'], check_return=True) # Allow the test driver to get full read and write access to the directory on the device, # as well as for the FIFOs. We'll need a world writable directory. device.RunShellCommand( ['mkdir', '-p', self._driver_details.device_directory()], check_return=True) # Make sure that the disk cache on the device resets to a clean state. device.RunShellCommand( ['rm', '-rf', self._driver_details.device_cache_directory()], check_return=True) device.EnableRoot() perf_control.PerfControl(device).SetPerfProfilingMode() # Required by webkit_support::GetWebKitRootDirFilePath(). # Other directories will be created automatically by adb push. device.RunShellCommand( ['mkdir', '-p', DEVICE_SOURCE_ROOT_DIR + 'chrome'], check_return=True) # Allow the test driver to get full read and write access to the directory on the device, # as well as for the FIFOs. We'll need a world writable directory. device.RunShellCommand( ['mkdir', '-p', self._driver_details.device_directory()], check_return=True) # Make sure that the disk cache on the device resets to a clean state. device.RunShellCommand( ['rm', '-rf', self._driver_details.device_cache_directory()], check_return=True) device_path = lambda *p: posixpath.join( self._driver_details.device_directory(), *p) device.Install(self._path_to_driver()) # Build up a list of what we want to push, including: host_device_tuples = [] # - the custom font files # TODO(sergeyu): Rename these files, they can be used on platforms # other than Android. host_device_tuples.append( (self._build_path('test_fonts/android_main_fonts.xml'), device_path('android_main_fonts.xml'))) host_device_tuples.append( (self._build_path('test_fonts/android_fallback_fonts.xml'), device_path('android_fallback_fonts.xml'))) for font_file in self._get_font_files(): host_device_tuples.append( (font_file, device_path('fonts', os.path.basename(font_file)))) # - the test resources host_device_tuples.extend( (self.host.filesystem.join(self.web_tests_dir(), resource), posixpath.join(DEVICE_WEB_TESTS_DIR, resource)) for resource in TEST_RESOURCES_TO_PUSH) # ... and then push them to the device. device.PushChangedFiles(host_device_tuples) device.RunShellCommand( ['mkdir', '-p', self._driver_details.device_fifo_directory()], check_return=True) device.RunShellCommand([ 'chmod', '-R', '777', self._driver_details.device_directory() ], check_return=True) device.RunShellCommand([ 'chmod', '-R', '777', self._driver_details.device_fifo_directory() ], check_return=True) # Mark this device as having been set up. self._devices.set_device_prepared(device.serial) log_safely('device prepared', throttled=False) def setup_device(device): try: _setup_device_impl(device) except (ScriptError, driver.DeviceFailure, device_errors.CommandFailedError, device_errors.CommandTimeoutError, device_errors.DeviceUnreachableError) as error: with lock: _log.warning('[%s] failed to prepare_device: %s', device.serial, error) devices = self._devices.usable_devices(self.host.executive) device_utils.DeviceUtils.parallel(devices).pMap(setup_device) if not self._devices.prepared_devices(): _log.error('Could not prepare any devices for testing.') return exit_codes.NO_DEVICES_EXIT_STATUS return exit_codes.OK_EXIT_STATUS def setup_test_run(self): super(AndroidPort, self).setup_test_run() # By setting this on the options object, we can propagate the list # of prepared devices to the workers (it is read in __init__()). if self._devices._prepared_devices: self._options.prepared_devices = self._devices.prepared_devices() else: # We were called with --no-build, so assume the devices are up to date. self._options.prepared_devices = [ d.get_serial() for d in self._devices.usable_devices(self.host.executive) ] def num_workers(self, requested_num_workers): return min(len(self._options.prepared_devices), requested_num_workers) def check_sys_deps(self): # _get_font_files() will throw if any of the required fonts is missing. self._get_font_files() return exit_codes.OK_EXIT_STATUS def requires_http_server(self): """Chromium Android runs tests on devices, and uses the HTTP server to serve the actual web tests to the test driver. """ return True def start_http_server(self, additional_dirs, number_of_drivers): additional_dirs[PERF_TEST_PATH_PREFIX] = self._perf_tests_dir() additional_dirs[WEB_TESTS_PATH_PREFIX] = self.web_tests_dir() super(AndroidPort, self).start_http_server(additional_dirs, number_of_drivers) def create_driver(self, worker_number, no_timeout=False): return ChromiumAndroidDriver( self, worker_number, driver_details=self._driver_details, android_devices=self._devices, # Force no timeout to avoid test driver timeouts before NRWT. no_timeout=True) def driver_cmd_line(self): # Override to return the actual test driver's command line. return self.create_driver(0)._android_driver_cmd_line([]) def clobber_old_port_specific_results(self): if not self.get_option('disable_breakpad'): self._dump_reader.clobber_old_results() # Overridden protected methods. def _build_path(self, *comps): return self._host_port._build_path(*comps) def _build_path_with_target(self, target, *comps): return self._host_port._build_path_with_target(target, *comps) def path_to_apache(self): return self._host_port.path_to_apache() def path_to_apache_config_file(self): return self._host_port.path_to_apache_config_file() def _path_to_driver(self, target=None): return self._build_path_with_target(target, self._driver_details.apk_name()) def _path_to_image_diff(self): return self._host_port._path_to_image_diff() def _shut_down_http_server(self, pid): return self._host_port._shut_down_http_server(pid) def _driver_class(self): return ChromiumAndroidDriver # Local private methods. @staticmethod def _android_server_process_constructor(port, server_name, cmd_line, env=None, more_logging=False): return server_process.ServerProcess(port, server_name, cmd_line, env, treat_no_data_as_crash=True, more_logging=more_logging)