| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import datetime |
| import logging |
| import os |
| import shutil |
| import tempfile |
| import threading |
| |
| from devil.android import device_blacklist |
| from devil.android import device_errors |
| from devil.android import device_utils |
| from devil.android import logcat_monitor |
| from devil.utils import file_utils |
| from devil.utils import parallelizer |
| from pylib import constants |
| from pylib.base import environment |
| |
| |
| def _DeviceCachePath(device): |
| file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial() |
| return os.path.join(constants.GetOutDirectory(), file_name) |
| |
| |
| class LocalDeviceEnvironment(environment.Environment): |
| |
| def __init__(self, args, _error_func): |
| super(LocalDeviceEnvironment, self).__init__() |
| self._blacklist = (device_blacklist.Blacklist(args.blacklist_file) |
| if args.blacklist_file |
| else None) |
| self._device_serial = args.test_device |
| self._devices_lock = threading.Lock() |
| self._devices = [] |
| self._concurrent_adb = args.enable_concurrent_adb |
| self._enable_device_cache = args.enable_device_cache |
| self._logcat_monitors = [] |
| self._logcat_output_dir = args.logcat_output_dir |
| self._logcat_output_file = args.logcat_output_file |
| self._max_tries = 1 + args.num_retries |
| self._skip_clear_data = args.skip_clear_data |
| self._tool_name = args.tool |
| |
| #override |
| def SetUp(self): |
| available_devices = device_utils.DeviceUtils.HealthyDevices( |
| self._blacklist, enable_device_files_cache=self._enable_device_cache, |
| default_retries=self._max_tries - 1) |
| if not available_devices: |
| raise device_errors.NoDevicesError |
| if self._device_serial: |
| self._devices = [d for d in available_devices |
| if d.adb.GetDeviceSerial() == self._device_serial] |
| if not self._devices: |
| raise device_errors.DeviceUnreachableError( |
| 'Could not find device %r' % self._device_serial) |
| else: |
| self._devices = available_devices |
| |
| if self._enable_device_cache: |
| for d in self._devices: |
| cache_path = _DeviceCachePath(d) |
| if os.path.exists(cache_path): |
| logging.info('Using device cache: %s', cache_path) |
| with open(cache_path) as f: |
| d.LoadCacheData(f.read()) |
| # Delete cached file so that any exceptions cause it to be cleared. |
| os.unlink(cache_path) |
| if self._logcat_output_file: |
| self._logcat_output_dir = tempfile.mkdtemp() |
| if self._logcat_output_dir: |
| for d in self._devices: |
| logcat_file = os.path.join( |
| self._logcat_output_dir, |
| '%s_%s' % (d.adb.GetDeviceSerial(), |
| datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%S'))) |
| monitor = logcat_monitor.LogcatMonitor( |
| d.adb, clear=True, output_file=logcat_file) |
| self._logcat_monitors.append(monitor) |
| monitor.Start() |
| |
| @property |
| def concurrent_adb(self): |
| return self._concurrent_adb |
| |
| @property |
| def devices(self): |
| if not self._devices: |
| raise device_errors.NoDevicesError() |
| return self._devices |
| |
| @property |
| def max_tries(self): |
| return self._max_tries |
| |
| @property |
| def parallel_devices(self): |
| return parallelizer.SyncParallelizer(self.devices) |
| |
| @property |
| def skip_clear_data(self): |
| return self._skip_clear_data |
| |
| @property |
| def tool(self): |
| return self._tool_name |
| |
| #override |
| def TearDown(self): |
| # Write the cache even when not using it so that it will be ready the first |
| # time that it is enabled. Writing it every time is also necessary so that |
| # an invalid cache can be flushed just by disabling it for one run. |
| for d in self._devices: |
| cache_path = _DeviceCachePath(d) |
| with open(cache_path, 'w') as f: |
| f.write(d.DumpCacheData()) |
| logging.info('Wrote device cache: %s', cache_path) |
| for m in self._logcat_monitors: |
| m.Stop() |
| m.Close() |
| if self._logcat_output_file: |
| file_utils.MergeFiles( |
| self._logcat_output_file, |
| [m.output_file for m in self._logcat_monitors]) |
| shutil.rmtree(self._logcat_output_dir) |
| |
| def BlacklistDevice(self, device, reason='local_device_failure'): |
| device_serial = device.adb.GetDeviceSerial() |
| if self._blacklist: |
| self._blacklist.Extend([device_serial], reason=reason) |
| with self._devices_lock: |
| self._devices = [d for d in self._devices if str(d) != device_serial] |
| |