• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import datetime
6import logging
7import os
8import shutil
9import tempfile
10import threading
11
12from devil.android import device_blacklist
13from devil.android import device_errors
14from devil.android import device_utils
15from devil.android import logcat_monitor
16from devil.utils import file_utils
17from devil.utils import parallelizer
18from pylib import constants
19from pylib.base import environment
20
21
22def _DeviceCachePath(device):
23  file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial()
24  return os.path.join(constants.GetOutDirectory(), file_name)
25
26
27class 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