blob: fce1d2dfc99212562850abab77890171c8424720 [file] [log] [blame]
# 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]