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

Side by Side Diff: tools/android/loading/log_requests.py

Issue 1619713002: Upgrade analyze.py and related scripts to new world order. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments Created 4 years, 11 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 | « tools/android/loading/log_parser.py ('k') | tools/android/loading/process_request_log.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #! /usr/bin/python
2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Loads a URL on an Android device, logging all the requests made to do it
7 to a JSON file using DevTools.
8 """
9
10 import contextlib
11 import httplib
12 import json
13 import logging
14 import optparse
15 import os
16 import sys
17
18 _SRC_DIR = os.path.abspath(os.path.join(
19 os.path.dirname(__file__), '..', '..', '..'))
20
21 sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'catapult', 'devil'))
22 from devil.android import device_utils
23
24 sys.path.append(os.path.join(_SRC_DIR, 'build', 'android'))
25 import devil_chromium
26
27 sys.path.append(os.path.join(_SRC_DIR, 'tools', 'telemetry'))
28 from telemetry.internal.backends.chrome_inspector import inspector_websocket
29 from telemetry.internal.backends.chrome_inspector import websocket
30
31 sys.path.append(os.path.join(_SRC_DIR, 'tools', 'chrome_proxy'))
32 from common import inspector_network
33
34 import device_setup
35
36
37 class AndroidRequestsLogger(object):
38 """Logs all the requests made to load a page on a device."""
39
40 def __init__(self, device):
41 """If device is None, we connect to a local chrome session."""
42 self.device = device
43 self._please_stop = False
44 self._main_frame_id = None
45 self._tracing_data = []
46
47 def _PageDataReceived(self, msg):
48 """Called when a Page event is received.
49
50 Records the main frame, and stops the recording once it has finished
51 loading.
52
53 Args:
54 msg: (dict) Message sent by DevTools.
55 """
56 if 'params' not in msg:
57 return
58 params = msg['params']
59 method = msg.get('method', None)
60 if method == 'Page.frameStartedLoading' and self._main_frame_id is None:
61 self._main_frame_id = params['frameId']
62 elif (method == 'Page.frameStoppedLoading'
63 and params['frameId'] == self._main_frame_id):
64 self._please_stop = True
65
66 def _TracingDataReceived(self, msg):
67 self._tracing_data.append(msg)
68
69 def _LogPageLoadInternal(self, url, clear_cache):
70 """Returns the collection of requests made to load a given URL.
71
72 Assumes that DevTools is available on http://localhost:DEVTOOLS_PORT.
73
74 Args:
75 url: URL to load.
76 clear_cache: Whether to clear the HTTP cache.
77
78 Returns:
79 [inspector_network.InspectorNetworkResponseData, ...]
80 """
81 self._main_frame_id = None
82 self._please_stop = False
83 r = httplib.HTTPConnection(
84 device_setup.DEVTOOLS_HOSTNAME, device_setup.DEVTOOLS_PORT)
85 r.request('GET', '/json')
86 response = r.getresponse()
87 if response.status != 200:
88 logging.error('Cannot connect to the remote target.')
89 return None
90 json_response = json.loads(response.read())
91 r.close()
92 websocket_url = json_response[0]['webSocketDebuggerUrl']
93 ws = inspector_websocket.InspectorWebsocket()
94 ws.Connect(websocket_url)
95 inspector = inspector_network.InspectorNetwork(ws)
96 if clear_cache:
97 inspector.ClearCache()
98 ws.SyncRequest({'method': 'Page.enable'})
99 ws.RegisterDomain('Page', self._PageDataReceived)
100 inspector.StartMonitoringNetwork()
101 ws.SendAndIgnoreResponse({'method': 'Page.navigate',
102 'params': {'url': url}})
103 while not self._please_stop:
104 try:
105 ws.DispatchNotifications()
106 except websocket.WebSocketTimeoutException as e:
107 logging.warning('Exception: ' + str(e))
108 break
109 if not self._please_stop:
110 logging.warning('Finished with timeout instead of page load')
111 inspector.StopMonitoringNetwork()
112 return inspector.GetResponseData()
113
114 def _LogTracingInternal(self, url):
115 self._main_frame_id = None
116 self._please_stop = False
117 r = httplib.HTTPConnection('localhost', device_setup.DEVTOOLS_PORT)
118 r.request('GET', '/json')
119 response = r.getresponse()
120 if response.status != 200:
121 logging.error('Cannot connect to the remote target.')
122 return None
123 json_response = json.loads(response.read())
124 r.close()
125 websocket_url = json_response[0]['webSocketDebuggerUrl']
126 ws = inspector_websocket.InspectorWebsocket()
127 ws.Connect(websocket_url)
128 ws.RegisterDomain('Tracing', self._TracingDataReceived)
129 logging.warning('Tracing.start: ' +
130 str(ws.SyncRequest({'method': 'Tracing.start',
131 'options': 'zork'})))
132 ws.SendAndIgnoreResponse({'method': 'Page.navigate',
133 'params': {'url': url}})
134 while not self._please_stop:
135 try:
136 ws.DispatchNotifications()
137 except websocket.WebSocketTimeoutException:
138 break
139 if not self._please_stop:
140 logging.warning('Finished with timeout instead of page load')
141 return {'events': self._tracing_data,
142 'end': ws.SyncRequest({'method': 'Tracing.end'})}
143
144
145 def LogPageLoad(self, url, clear_cache, package):
146 """Returns the collection of requests made to load a given URL on a device.
147
148 Args:
149 url: (str) URL to load on the device.
150 clear_cache: (bool) Whether to clear the HTTP cache.
151
152 Returns:
153 See _LogPageLoadInternal().
154 """
155 return device_setup.SetUpAndExecute(
156 self.device, package,
157 lambda: self._LogPageLoadInternal(url, clear_cache))
158
159 def LogTracing(self, url):
160 """Log tracing events from a load of the given URL.
161
162 TODO(mattcary): This doesn't work. It would be best to log tracing
163 simultaneously with network requests, but as that wasn't working the tracing
164 logging was broken out separately. It still doesn't work...
165 """
166 return device_setup.SetUpAndExecute(
167 self.device, 'chrome', lambda: self._LogTracingInternal(url))
168
169
170 def _ResponseDataToJson(data):
171 """Converts a list of inspector_network.InspectorNetworkResponseData to JSON.
172
173 Args:
174 data: as returned by _LogPageLoad()
175
176 Returns:
177 A JSON file with the following format:
178 [request1, request2, ...], and a request is:
179 {'status': str, 'headers': dict, 'request_headers': dict,
180 'timestamp': double, 'timing': dict, 'url': str,
181 'served_from_cache': bool, 'initiator': str})
182 """
183 result = []
184 for r in data:
185 result.append({'status': r.status,
186 'headers': r.headers,
187 'request_headers': r.request_headers,
188 'timestamp': r.timestamp,
189 'timing': r.timing,
190 'url': r.url,
191 'served_from_cache': r.served_from_cache,
192 'initiator': r.initiator})
193 return json.dumps(result)
194
195
196 def _CreateOptionParser():
197 """Returns the option parser for this tool."""
198 parser = optparse.OptionParser(description='Starts a browser on an Android '
199 'device, gathers the requests made to load a '
200 'page and dumps it to a JSON file.')
201 parser.add_option('--url', help='URL to load.',
202 default='https://www.google.com', metavar='URL')
203 parser.add_option('--output', help='Output file.', default='result.json')
204 parser.add_option('--no-clear-cache', help=('Do not clear the HTTP cache '
205 'before loading the URL.'),
206 default=True, action='store_false', dest='clear_cache')
207 parser.add_option('--package', help='Package info for chrome build. '
208 'See build/android/pylib/constants.',
209 default='chrome')
210 parser.add_option('--local', action='store_true', default=False,
211 help='Connect to local chrome session rather than android.')
212 return parser
213
214
215 def main():
216 logging.basicConfig(level=logging.WARNING)
217 parser = _CreateOptionParser()
218 options, _ = parser.parse_args()
219
220 devil_chromium.Initialize()
221
222 if options.local:
223 device = None
224 else:
225 devices = device_utils.DeviceUtils.HealthyDevices()
226 device = devices[0]
227
228 request_logger = AndroidRequestsLogger(device)
229 response_data = request_logger.LogPageLoad(
230 options.url, options.clear_cache, options.package)
231 json_data = _ResponseDataToJson(response_data)
232 with open(options.output, 'w') as f:
233 f.write(json_data)
234
235
236 if __name__ == '__main__':
237 main()
OLDNEW
« no previous file with comments | « tools/android/loading/log_parser.py ('k') | tools/android/loading/process_request_log.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698