Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1796)

Side by Side Diff: build/android/pylib/local/device/local_device_environment.py

Issue 2144823003: [Android] Blacklist devices on failures during environment set up + tear down. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | build/android/pylib/local/device/local_device_gtest_run.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import datetime 5 import datetime
6 import functools
6 import logging 7 import logging
7 import os 8 import os
8 import shutil 9 import shutil
9 import tempfile 10 import tempfile
10 import threading 11 import threading
11 12
13 from devil import base_error
12 from devil.android import device_blacklist 14 from devil.android import device_blacklist
13 from devil.android import device_errors 15 from devil.android import device_errors
14 from devil.android import device_list 16 from devil.android import device_list
15 from devil.android import device_utils 17 from devil.android import device_utils
16 from devil.android import logcat_monitor 18 from devil.android import logcat_monitor
17 from devil.utils import file_utils 19 from devil.utils import file_utils
18 from devil.utils import parallelizer 20 from devil.utils import parallelizer
19 from pylib import constants 21 from pylib import constants
20 from pylib.base import environment 22 from pylib.base import environment
21 23
22 24
23 def _DeviceCachePath(device): 25 def _DeviceCachePath(device):
24 file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial() 26 file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial()
25 return os.path.join(constants.GetOutDirectory(), file_name) 27 return os.path.join(constants.GetOutDirectory(), file_name)
26 28
27 29
30 def handle_shard_failures(f):
31 """A decorator that handles device failures for per-device functions.
32
33 Args:
34 f: the function being decorated. The function must take at least one
35 argument, and that argument must be the device.
36 """
37 return handle_shard_failures_with(None)(f)
38
39
40 # TODO(jbudorick): Refactor this to work as a decorator or context manager.
41 def handle_shard_failures_with(on_failure):
42 """A decorator that handles device failures for per-device functions.
43
44 This calls on_failure in the event of a failure.
45
46 Args:
47 f: the function being decorated. The function must take at least one
48 argument, and that argument must be the device.
49 on_failure: A binary function to call on failure.
50 """
51 def decorator(f):
52 @functools.wraps(f)
53 def wrapper(dev, *args, **kwargs):
54 try:
55 return f(dev, *args, **kwargs)
56 except device_errors.CommandTimeoutError:
57 logging.exception('Shard timed out: %s(%s)', f.__name__, str(dev))
58 except device_errors.DeviceUnreachableError:
59 logging.exception('Shard died: %s(%s)', f.__name__, str(dev))
60 except base_error.BaseError:
61 logging.exception('Shard failed: %s(%s)', f.__name__, str(dev))
62 except SystemExit:
63 logging.exception('Shard killed: %s(%s)', f.__name__, str(dev))
64 raise
65 if on_failure:
66 on_failure(dev, f.__name__)
67 return None
68
69 return wrapper
70
71 return decorator
72
73
28 class LocalDeviceEnvironment(environment.Environment): 74 class LocalDeviceEnvironment(environment.Environment):
29 75
30 def __init__(self, args, _error_func): 76 def __init__(self, args, _error_func):
31 super(LocalDeviceEnvironment, self).__init__() 77 super(LocalDeviceEnvironment, self).__init__()
32 self._blacklist = (device_blacklist.Blacklist(args.blacklist_file) 78 self._blacklist = (device_blacklist.Blacklist(args.blacklist_file)
33 if args.blacklist_file 79 if args.blacklist_file
34 else None) 80 else None)
35 self._device_serial = args.test_device 81 self._device_serial = args.test_device
36 self._devices_lock = threading.Lock() 82 self._devices_lock = threading.Lock()
37 self._devices = [] 83 self._devices = []
(...skipping 22 matching lines...) Expand all
60 'Read device list %s from target devices file.', str(device_arg)) 106 'Read device list %s from target devices file.', str(device_arg))
61 elif self._device_serial: 107 elif self._device_serial:
62 device_arg = self._device_serial 108 device_arg = self._device_serial
63 109
64 self._devices = device_utils.DeviceUtils.HealthyDevices( 110 self._devices = device_utils.DeviceUtils.HealthyDevices(
65 self._blacklist, enable_device_files_cache=self._enable_device_cache, 111 self._blacklist, enable_device_files_cache=self._enable_device_cache,
66 default_retries=self._max_tries - 1, device_arg=device_arg) 112 default_retries=self._max_tries - 1, device_arg=device_arg)
67 if not self._devices: 113 if not self._devices:
68 raise device_errors.NoDevicesError 114 raise device_errors.NoDevicesError
69 115
70 if self._enable_device_cache: 116 if self._logcat_output_file:
71 for d in self._devices: 117 self._logcat_output_dir = tempfile.mkdtemp()
118
119 @handle_shard_failures_with(on_failure=self.BlacklistDevice)
120 def prepare_device(d):
121 if self._enable_device_cache:
72 cache_path = _DeviceCachePath(d) 122 cache_path = _DeviceCachePath(d)
73 if os.path.exists(cache_path): 123 if os.path.exists(cache_path):
74 logging.info('Using device cache: %s', cache_path) 124 logging.info('Using device cache: %s', cache_path)
75 with open(cache_path) as f: 125 with open(cache_path) as f:
76 d.LoadCacheData(f.read()) 126 d.LoadCacheData(f.read())
77 # Delete cached file so that any exceptions cause it to be cleared. 127 # Delete cached file so that any exceptions cause it to be cleared.
78 os.unlink(cache_path) 128 os.unlink(cache_path)
79 if self._logcat_output_file: 129
80 self._logcat_output_dir = tempfile.mkdtemp() 130 if self._logcat_output_dir:
81 if self._logcat_output_dir:
82 for d in self._devices:
83 logcat_file = os.path.join( 131 logcat_file = os.path.join(
84 self._logcat_output_dir, 132 self._logcat_output_dir,
85 '%s_%s' % (d.adb.GetDeviceSerial(), 133 '%s_%s' % (d.adb.GetDeviceSerial(),
86 datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%S'))) 134 datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%S')))
87 monitor = logcat_monitor.LogcatMonitor( 135 monitor = logcat_monitor.LogcatMonitor(
88 d.adb, clear=True, output_file=logcat_file) 136 d.adb, clear=True, output_file=logcat_file)
89 self._logcat_monitors.append(monitor) 137 self._logcat_monitors.append(monitor)
90 monitor.Start() 138 monitor.Start()
91 139
140 self.parallel_devices.pMap(prepare_device)
141
92 @property 142 @property
93 def blacklist(self): 143 def blacklist(self):
94 return self._blacklist 144 return self._blacklist
95 145
96 @property 146 @property
97 def concurrent_adb(self): 147 def concurrent_adb(self):
98 return self._concurrent_adb 148 return self._concurrent_adb
99 149
100 @property 150 @property
101 def devices(self): 151 def devices(self):
(...skipping 12 matching lines...) Expand all
114 @property 164 @property
115 def skip_clear_data(self): 165 def skip_clear_data(self):
116 return self._skip_clear_data 166 return self._skip_clear_data
117 167
118 @property 168 @property
119 def tool(self): 169 def tool(self):
120 return self._tool_name 170 return self._tool_name
121 171
122 #override 172 #override
123 def TearDown(self): 173 def TearDown(self):
124 # Write the cache even when not using it so that it will be ready the first 174 @handle_shard_failures_with(on_failure=self.BlacklistDevice)
125 # time that it is enabled. Writing it every time is also necessary so that 175 def tear_down_device(d):
126 # an invalid cache can be flushed just by disabling it for one run. 176 # Write the cache even when not using it so that it will be ready the
127 for d in self._devices: 177 # first time that it is enabled. Writing it every time is also necessary
178 # so that an invalid cache can be flushed just by disabling it for one
179 # run.
128 cache_path = _DeviceCachePath(d) 180 cache_path = _DeviceCachePath(d)
129 with open(cache_path, 'w') as f: 181 with open(cache_path, 'w') as f:
130 f.write(d.DumpCacheData()) 182 f.write(d.DumpCacheData())
131 logging.info('Wrote device cache: %s', cache_path) 183 logging.info('Wrote device cache: %s', cache_path)
184
185 self.parallel_devices.pMap(tear_down_device)
186
132 for m in self._logcat_monitors: 187 for m in self._logcat_monitors:
133 m.Stop() 188 try:
134 m.Close() 189 m.Stop()
190 m.Close()
191 except base_error.BaseError:
192 logging.exception('Failed to stop logcat monitor for %s',
193 m.adb.GetDeviceSerial())
194
135 if self._logcat_output_file: 195 if self._logcat_output_file:
136 file_utils.MergeFiles( 196 file_utils.MergeFiles(
137 self._logcat_output_file, 197 self._logcat_output_file,
138 [m.output_file for m in self._logcat_monitors]) 198 [m.output_file for m in self._logcat_monitors])
139 shutil.rmtree(self._logcat_output_dir) 199 shutil.rmtree(self._logcat_output_dir)
140 200
141 def BlacklistDevice(self, device, reason='local_device_failure'): 201 def BlacklistDevice(self, device, reason='local_device_failure'):
142 device_serial = device.adb.GetDeviceSerial() 202 device_serial = device.adb.GetDeviceSerial()
143 if self._blacklist: 203 if self._blacklist:
144 self._blacklist.Extend([device_serial], reason=reason) 204 self._blacklist.Extend([device_serial], reason=reason)
145 with self._devices_lock: 205 with self._devices_lock:
146 self._devices = [d for d in self._devices if str(d) != device_serial] 206 self._devices = [d for d in self._devices if str(d) != device_serial]
147 207
OLDNEW
« no previous file with comments | « no previous file | build/android/pylib/local/device/local_device_gtest_run.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698