OLD | NEW |
---|---|
(Empty) | |
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 import logging | |
5 import os | |
6 import re | |
7 import subprocess | |
8 import sys | |
9 | |
10 from telemetry.core import android_app | |
11 from telemetry.core import exceptions | |
12 from telemetry.core import platform | |
13 from telemetry.core import util | |
14 from telemetry.core import wpr_modes | |
15 from telemetry.core.backends import adb_commands | |
16 from telemetry.core.backends import android_app_backend | |
17 from telemetry.core.platform import android_device | |
18 from telemetry.user_story import shared_user_story_state | |
19 from telemetry.web_perf import timeline_based_measurement | |
20 | |
21 try: | |
22 import psutil # pylint: disable=import-error | |
23 except ImportError: | |
24 psutil = None | |
25 | |
26 | |
27 class SharedAppState(shared_user_story_state.SharedUserStoryState): | |
28 def __init__(self, test, finder_options, user_story_set): | |
29 super(SharedAppState, self).__init__(test, finder_options, user_story_set) | |
30 # SharedAppState only supports TimelineBasedMeasurement (TBM). | |
31 # TODO(slamm): This SharedAppState does not yet interact with TBM yet | |
32 # because TBM still has browser based logic. | |
33 assert isinstance(test, timeline_based_measurement.TimelineBasedMeasurement) | |
34 self._finder_options = finder_options | |
35 self._android_app = None | |
36 self._current_user_story = None | |
37 self._platform = GetPlatform(finder_options) | |
38 assert self._platform, 'Unable to create android platform.' | |
39 | |
40 @property | |
41 def platform(self): | |
42 return self._platform | |
43 | |
44 @property | |
45 def _platform_backend(self): | |
nednguyen
2014/12/05 20:15:22
This is a hack. If there is no plan to fix this in
slamm
2014/12/06 00:40:00
Done.
slamm
2014/12/06 00:40:00
Done.
| |
46 return self._platform._platform_backend | |
47 | |
48 def _PrepareWpr(self, network_controller, archive_path, | |
49 make_javascript_deterministic=True): | |
50 browser_options = self._finder_options.browser_options | |
51 if self._finder_options.use_live_sites: | |
52 browser_options.wpr_mode = wpr_modes.WPR_OFF | |
53 elif browser_options.wpr_mode != wpr_modes.WPR_RECORD: | |
54 browser_options.wpr_mode = ( | |
55 wpr_modes.WPR_REPLAY | |
56 if archive_path and os.path.isfile(archive_path) | |
57 else wpr_modes.WPR_OFF) | |
58 | |
59 # Replay's life-cycle is tied to the browser. Start and Stop are handled by | |
60 # platform_backend.DidCreateBrowser and platform_backend.WillCloseBrowser, | |
61 # respectively. | |
62 # TODO(slamm): Update life-cycle comment with https://crbug.com/424777 fix. | |
63 wpr_mode = browser_options.wpr_mode | |
64 network_controller.SetReplayArgs( | |
65 archive_path, wpr_mode, browser_options.netsim, | |
66 browser_options.extra_wpr_args, make_javascript_deterministic) | |
67 | |
68 def WillRunUserStory(self, user_story): | |
69 assert not self._android_app | |
70 self._current_user_story = user_story | |
71 #self._PrepareWpr(self.platform.network_controller, user_story.archive_path) | |
72 | |
73 # TODO(chrishenry): Should this be moved to | |
74 # SharedAndroidAppState.DidRunUserStory? | |
75 self._platform_backend.DismissCrashDialogIfNeeded() | |
76 | |
77 start_intent = user_story.start_intent | |
78 platform_backend = self.platform._platform_backend # pylint: disable=W0212 | |
79 app_backend = android_app_backend.AndroidAppBackend( | |
80 platform_backend, start_intent) | |
81 self._android_app = android_app.AndroidApp(app_backend, platform_backend) | |
82 | |
83 def RunUserStory(self, results): | |
84 # CHEAT HAXX0R!! | |
85 self._current_user_story.Run() | |
86 | |
87 def DidRunUserStory(self, results): | |
88 if self._android_app: | |
89 self._android_app.Close() | |
90 self._android_app = None | |
91 | |
92 def GetTestExpectationAndSkipValue(self, expectations): | |
93 # TODO(chrishenry): Implement this properly. | |
94 return 'pass', None | |
95 | |
96 def TearDownState(self, results): | |
97 pass | |
98 | |
99 | |
100 def GetPlatform(finder_options): | |
101 """Finds all the desktop browsers available on this machine.""" | |
102 if not CanFindDevices(): | |
103 logging.info('No adb command found. ' + | |
104 'Will not try searching for Android browsers.') | |
105 return None | |
106 | |
107 if finder_options.android_device: | |
108 devices = [android_device.AndroidDevice( | |
109 finder_options.android_device, | |
110 enable_performance_mode=not finder_options.no_performance_mode)] | |
111 else: | |
112 devices = android_device.AndroidDevice.GetAllConnectedDevices() | |
113 | |
114 if len(devices) == 0: | |
115 logging.info('No android devices found.') | |
116 return None | |
117 elif len(devices) > 1: | |
118 logging.warn( | |
119 'Multiple devices attached. Please specify one of the following:\n' + | |
120 '\n'.join([' --device=%s' % d.device_id for d in devices])) | |
121 return None | |
122 | |
123 try: | |
124 android_platform = platform.GetPlatformForDevice(devices[0]) | |
125 except exceptions.PlatformError: | |
126 return None | |
127 | |
128 # Host side workaround for crbug.com/268450 (adb instability). | |
129 # The adb server has a race which is mitigated by binding to a single core. | |
130 if psutil: | |
131 for proc in psutil.process_iter(): | |
132 try: | |
133 if 'adb' in proc.name: | |
134 if 'cpu_affinity' in dir(proc): | |
135 proc.cpu_affinity([0]) # New versions of psutil. | |
136 elif 'set_cpu_affinity' in dir(proc): | |
137 proc.set_cpu_affinity([0]) # Older versions. | |
138 else: | |
139 logging.warn( | |
140 'Cannot set CPU affinity due to stale psutil version: %s', | |
141 '.'.join(str(x) for x in psutil.version_info)) | |
142 except (psutil.NoSuchProcess, psutil.AccessDenied): | |
143 logging.warn('Failed to set adb process CPU affinity') | |
144 | |
145 return android_platform | |
146 | |
147 | |
148 def CanFindDevices(): | |
149 if not adb_commands.IsAndroidSupported(): | |
150 logging.info('Android build commands unavailable on this machine. Have ' | |
151 'you installed Android build dependencies?') | |
152 return False | |
153 | |
154 try: | |
155 with open(os.devnull, 'w') as devnull: | |
156 proc = subprocess.Popen( | |
157 ['adb', 'devices'], | |
158 stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=devnull) | |
159 stdout, _ = proc.communicate() | |
160 if re.search(re.escape('????????????\tno permissions'), stdout) != None: | |
161 logging.warn('adb devices reported a permissions error. Consider ' | |
162 'restarting adb as root:') | |
163 logging.warn(' adb kill-server') | |
164 logging.warn(' sudo `which adb` devices\n\n') | |
165 return True | |
166 except OSError: | |
167 platform_tools_path = os.path.join(util.GetChromiumSrcDir(), | |
168 'third_party', 'android_tools', 'sdk', 'platform-tools') | |
169 if (sys.platform.startswith('linux') and | |
170 os.path.exists(os.path.join(platform_tools_path, 'adb'))): | |
171 os.environ['PATH'] = os.pathsep.join([platform_tools_path, | |
172 os.environ['PATH']]) | |
173 return True | |
174 return False | |
OLD | NEW |