Home | History | Annotate | Download | only in device
      1 # Copyright 2014 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import datetime
      6 import logging
      7 import os
      8 import shutil
      9 import tempfile
     10 import threading
     11 
     12 from devil.android import device_blacklist
     13 from devil.android import device_errors
     14 from devil.android import device_utils
     15 from devil.android import logcat_monitor
     16 from devil.utils import file_utils
     17 from devil.utils import parallelizer
     18 from pylib import constants
     19 from pylib.base import environment
     20 
     21 
     22 def _DeviceCachePath(device):
     23   file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial()
     24   return os.path.join(constants.GetOutDirectory(), file_name)
     25 
     26 
     27 class LocalDeviceEnvironment(environment.Environment):
     28 
     29   def __init__(self, args, _error_func):
     30     super(LocalDeviceEnvironment, self).__init__()
     31     self._blacklist = (device_blacklist.Blacklist(args.blacklist_file)
     32                        if args.blacklist_file
     33                        else None)
     34     self._device_serial = args.test_device
     35     self._devices_lock = threading.Lock()
     36     self._devices = []
     37     self._concurrent_adb = args.enable_concurrent_adb
     38     self._enable_device_cache = args.enable_device_cache
     39     self._logcat_monitors = []
     40     self._logcat_output_dir = args.logcat_output_dir
     41     self._logcat_output_file = args.logcat_output_file
     42     self._max_tries = 1 + args.num_retries
     43     self._skip_clear_data = args.skip_clear_data
     44     self._tool_name = args.tool
     45 
     46   #override
     47   def SetUp(self):
     48     available_devices = device_utils.DeviceUtils.HealthyDevices(
     49         self._blacklist, enable_device_files_cache=self._enable_device_cache,
     50         default_retries=self._max_tries - 1)
     51     if not available_devices:
     52       raise device_errors.NoDevicesError
     53     if self._device_serial:
     54       self._devices = [d for d in available_devices
     55                        if d.adb.GetDeviceSerial() == self._device_serial]
     56       if not self._devices:
     57         raise device_errors.DeviceUnreachableError(
     58             'Could not find device %r' % self._device_serial)
     59     else:
     60       self._devices = available_devices
     61 
     62     if self._enable_device_cache:
     63       for d in self._devices:
     64         cache_path = _DeviceCachePath(d)
     65         if os.path.exists(cache_path):
     66           logging.info('Using device cache: %s', cache_path)
     67           with open(cache_path) as f:
     68             d.LoadCacheData(f.read())
     69           # Delete cached file so that any exceptions cause it to be cleared.
     70           os.unlink(cache_path)
     71     if self._logcat_output_file:
     72       self._logcat_output_dir = tempfile.mkdtemp()
     73     if self._logcat_output_dir:
     74       for d in self._devices:
     75         logcat_file = os.path.join(
     76             self._logcat_output_dir,
     77             '%s_%s' % (d.adb.GetDeviceSerial(),
     78                        datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%S')))
     79         monitor = logcat_monitor.LogcatMonitor(
     80             d.adb, clear=True, output_file=logcat_file)
     81         self._logcat_monitors.append(monitor)
     82         monitor.Start()
     83 
     84   @property
     85   def concurrent_adb(self):
     86     return self._concurrent_adb
     87 
     88   @property
     89   def devices(self):
     90     if not self._devices:
     91       raise device_errors.NoDevicesError()
     92     return self._devices
     93 
     94   @property
     95   def max_tries(self):
     96     return self._max_tries
     97 
     98   @property
     99   def parallel_devices(self):
    100     return parallelizer.SyncParallelizer(self.devices)
    101 
    102   @property
    103   def skip_clear_data(self):
    104     return self._skip_clear_data
    105 
    106   @property
    107   def tool(self):
    108     return self._tool_name
    109 
    110   #override
    111   def TearDown(self):
    112     # Write the cache even when not using it so that it will be ready the first
    113     # time that it is enabled. Writing it every time is also necessary so that
    114     # an invalid cache can be flushed just by disabling it for one run.
    115     for d in self._devices:
    116       cache_path = _DeviceCachePath(d)
    117       with open(cache_path, 'w') as f:
    118         f.write(d.DumpCacheData())
    119         logging.info('Wrote device cache: %s', cache_path)
    120     for m in self._logcat_monitors:
    121       m.Stop()
    122       m.Close()
    123     if self._logcat_output_file:
    124       file_utils.MergeFiles(
    125           self._logcat_output_file,
    126           [m.output_file for m in self._logcat_monitors])
    127       shutil.rmtree(self._logcat_output_dir)
    128 
    129   def BlacklistDevice(self, device, reason='local_device_failure'):
    130     device_serial = device.adb.GetDeviceSerial()
    131     if self._blacklist:
    132       self._blacklist.Extend([device_serial], reason=reason)
    133     with self._devices_lock:
    134       self._devices = [d for d in self._devices if str(d) != device_serial]
    135 
    136