Exemple #1
0
    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(
                'Layout 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)
Exemple #2
0
    def __init__(self, host, port_name, **kwargs):
        super(AndroidPort, self).__init__(host, port_name, **kwargs)

        self._operating_system = 'android'
        self._version = 'icecreamsandwich'

        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('Layout 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)
Exemple #3
0
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 = {"icecreamsandwich": ["android"] + linux.LinuxPort.latest_platform_fallback_path()}

    # Android has aac and mp3 codecs built in.
    PORT_HAS_AUDIO_CODECS_BUILT_IN = True

    BUILD_REQUIREMENTS_URL = "https://www.chromium.org/developers/how-tos/android-build-instructions"

    def __init__(self, host, port_name, **kwargs):
        super(AndroidPort, self).__init__(host, port_name, **kwargs)

        self._operating_system = "android"
        self._version = "icecreamsandwich"

        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("Layout 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_flag(self):
        return super(AndroidPort, self).additional_driver_flag() + 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(
                test_run_results.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_wdiff(self, more_logging=True):
        return self._host_port.check_wdiff(more_logging)

    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):
        # Printer objects aren't threadsafe, so we need to protect calls to them.
        lock = threading.Lock()
        pool = None

        # 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.
        def setup_device(worker_number):
            d = self.create_driver(worker_number)
            serial = d._device.serial  # pylint: disable=protected-access

            def log_safely(msg, throttled=True):
                if throttled:
                    callback = printer.write_throttled_update
                else:
                    callback = printer.write_update
                with lock:
                    callback("[%s] %s" % (serial, msg))

            log_safely("preparing device", throttled=False)
            try:
                d._setup_test(log_safely)
                log_safely("device prepared", throttled=False)
            except (ScriptError, driver.DeviceFailure) as e:
                with lock:
                    _log.warning("[%s] failed to prepare_device: %s", serial, str(e))
            except KeyboardInterrupt:
                if pool:
                    pool.terminate()

        # FIXME: It would be nice if we knew how many workers we needed.
        num_workers = self.default_child_processes()
        num_child_processes = int(self.get_option("child_processes"))
        if num_child_processes:
            num_workers = min(num_workers, num_child_processes)
        if num_workers > 1:
            pool = ThreadPool(num_workers)
            try:
                pool.map(setup_device, range(num_workers))
            except KeyboardInterrupt:
                pool.terminate()
                raise
        else:
            setup_device(0)

        if not self._devices.prepared_devices():
            _log.error("Could not prepare any devices for testing.")
            return test_run_results.NO_DEVICES_EXIT_STATUS
        return test_run_results.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, needs_http):
        for (font_dirs, font_file, package) in HOST_FONT_FILES:
            exists = False
            for font_dir in font_dirs:
                font_path = font_dir + font_file
                if self._check_file_exists(font_path, "", more_logging=False):
                    exists = True
                    break
            if not exists:
                _log.error(
                    "You are missing %s under %s. Try installing %s. See build instructions.",
                    font_file,
                    font_dirs,
                    package,
                )
                return test_run_results.SYS_DEPS_EXIT_STATUS
        return test_run_results.OK_EXIT_STATUS

    def requires_http_server(self):
        """Chromium Android runs tests on devices, and uses the HTTP server to
        serve the actual layout 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[LAYOUT_TEST_PATH_PREFIX] = self.layout_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,
            pixel_tests=self.get_option("pixel_tests"),
            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(self.get_option("pixel_tests"), [])

    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 _path_to_wdiff(self):
        return self._host_port._path_to_wdiff()

    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):
        # We need universal_newlines=True, because 'adb shell' for some unknown reason
        # does newline conversion of unix-style LF into win-style CRLF (and we need
        # to convert that back). This can cause headaches elsewhere because
        # server_process' stdout and stderr are now unicode file-like objects,
        # not binary file-like objects like all of the other ports are.
        # FIXME: crbug.com/496983.
        return server_process.ServerProcess(
            port,
            server_name,
            cmd_line,
            env,
            universal_newlines=True,
            treat_no_data_as_crash=True,
            more_logging=more_logging,
        )
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 = {'icecreamsandwich': ['android'] + linux.LinuxPort.latest_platform_fallback_path()}

    # Android has aac and mp3 codecs built in.
    PORT_HAS_AUDIO_CODECS_BUILT_IN = True

    BUILD_REQUIREMENTS_URL = 'https://www.chromium.org/developers/how-tos/android-build-instructions'

    def __init__(self, host, port_name, **kwargs):
        super(AndroidPort, self).__init__(host, port_name, **kwargs)

        self._operating_system = 'android'
        self._version = 'icecreamsandwich'

        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('Layout 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_flag(self):
        return super(AndroidPort, self).additional_driver_flag() + \
            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(test_run_results.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_wdiff(self, more_logging=True):
        return self._host_port.check_wdiff(more_logging)

    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):
        # Printer objects aren't threadsafe, so we need to protect calls to them.
        lock = threading.Lock()
        pool = None

        # 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.
        def setup_device(worker_number):
            d = self.create_driver(worker_number)
            serial = d._device.serial  # pylint: disable=protected-access

            def log_safely(msg, throttled=True):
                if throttled:
                    callback = printer.write_throttled_update
                else:
                    callback = printer.write_update
                with lock:
                    callback("[%s] %s" % (serial, msg))

            log_safely("preparing device", throttled=False)
            try:
                d._setup_test(log_safely)
                log_safely("device prepared", throttled=False)
            except (ScriptError, driver.DeviceFailure) as e:
                with lock:
                    _log.warning("[%s] failed to prepare_device: %s", serial, str(e))
            except KeyboardInterrupt:
                if pool:
                    pool.terminate()

        # FIXME: It would be nice if we knew how many workers we needed.
        num_workers = self.default_child_processes()
        num_child_processes = int(self.get_option('child_processes'))
        if num_child_processes:
            num_workers = min(num_workers, num_child_processes)
        if num_workers > 1:
            pool = ThreadPool(num_workers)
            try:
                pool.map(setup_device, range(num_workers))
            except KeyboardInterrupt:
                pool.terminate()
                raise
        else:
            setup_device(0)

        if not self._devices.prepared_devices():
            _log.error('Could not prepare any devices for testing.')
            return test_run_results.NO_DEVICES_EXIT_STATUS
        return test_run_results.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, needs_http):
        for (font_dirs, font_file, package) in HOST_FONT_FILES:
            exists = False
            for font_dir in font_dirs:
                font_path = font_dir + font_file
                if self._check_file_exists(font_path, '', more_logging=False):
                    exists = True
                    break
            if not exists:
                _log.error('You are missing %s under %s. Try installing %s. See build instructions.',
                           font_file, font_dirs, package)
                return test_run_results.SYS_DEPS_EXIT_STATUS
        return test_run_results.OK_EXIT_STATUS

    def requires_http_server(self):
        """Chromium Android runs tests on devices, and uses the HTTP server to
        serve the actual layout 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[LAYOUT_TEST_PATH_PREFIX] = self.layout_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, pixel_tests=self.get_option('pixel_tests'),
                                     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(self.get_option('pixel_tests'), [])

    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 _path_to_wdiff(self):
        return self._host_port._path_to_wdiff()

    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):
        # We need universal_newlines=True, because 'adb shell' for some unknown reason
        # does newline conversion of unix-style LF into win-style CRLF (and we need
        # to convert that back). This can cause headaches elsewhere because
        # server_process' stdout and stderr are now unicode file-like objects,
        # not binary file-like objects like all of the other ports are.
        # FIXME: crbug.com/496983.
        return server_process.ServerProcess(port, server_name, cmd_line, env,
                                            universal_newlines=True, treat_no_data_as_crash=True, more_logging=more_logging)
Exemple #5
0
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('Layout 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('android_main_fonts.xml'),
                 device_path('android_main_fonts.xml')))
            host_device_tuples.append(
                (self._build_path('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.layout_tests_dir(), resource),
                 posixpath.join(DEVICE_LAYOUT_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', 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, needs_http):
        # _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 layout 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[LAYOUT_TEST_PATH_PREFIX] = self.layout_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, pixel_tests=self.get_option('pixel_tests'),
                                     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(self.get_option('pixel_tests'), [])

    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)