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