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

Side by Side Diff: mojo/devtools/common/devtoolslib/android_shell.py

Issue 1381863004: Fix mojo_ tools on the first run after adb kill-server. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Address Ben's comments. Created 5 years, 2 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 | mojo/devtools/common/devtoolslib/android_shell_unittest.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 atexit 5 import atexit
6 import hashlib 6 import hashlib
7 import json 7 import json
8 import logging 8 import logging
9 import os 9 import os
10 import os.path 10 import os.path
(...skipping 20 matching lines...) Expand all
31 ] 31 ]
32 32
33 # Tags used by native logging reflected in the logcat. 33 # Tags used by native logging reflected in the logcat.
34 _LOGCAT_NATIVE_TAGS = [ 34 _LOGCAT_NATIVE_TAGS = [
35 'chromium', 35 'chromium',
36 'sky', 36 'sky',
37 ] 37 ]
38 38
39 _MOJO_SHELL_PACKAGE_NAME = 'org.chromium.mojo.shell' 39 _MOJO_SHELL_PACKAGE_NAME = 'org.chromium.mojo.shell'
40 40
41 # Used to parse the output of `adb devices`.
42 _ADB_DEVICES_HEADER = 'List of devices attached'
43
41 44
42 _logger = logging.getLogger() 45 _logger = logging.getLogger()
43 46
44 47
45 def _exit_if_needed(process): 48 def _exit_if_needed(process):
46 """Exits |process| if it is still alive.""" 49 """Exits |process| if it is still alive."""
47 if process.poll() is None: 50 if process.poll() is None:
48 process.kill() 51 process.kill()
49 52
50 53
51 def _find_available_port(netstat_output, max_attempts=10000): 54 def _find_available_port(netstat_output, max_attempts=10000):
52 opened = [int(x.strip().split()[3].split(':')[1]) 55 opened = [int(x.strip().split()[3].split(':')[1])
53 for x in netstat_output if x.startswith(' tcp')] 56 for x in netstat_output if x.startswith(' tcp')]
54 for _ in xrange(max_attempts): 57 for _ in xrange(max_attempts):
55 port = random.randint(4096, 16384) 58 port = random.randint(4096, 16384)
56 if port not in opened: 59 if port not in opened:
57 return port 60 return port
58 else: 61 else:
59 raise Exception('Failed to identify an available port.') 62 raise Exception('Failed to identify an available port.')
60 63
61 64
62 def _find_available_host_port(): 65 def _find_available_host_port():
63 netstat_output = subprocess.check_output(['netstat']) 66 netstat_output = subprocess.check_output(['netstat'])
64 return _find_available_port(netstat_output) 67 return _find_available_port(netstat_output)
65 68
69 def parse_adb_devices_output(adb_devices_output):
70 """Parses the output of the `adb devices` command, returning a dictionary
71 mapping device id to the status of the device, as printed by `adb devices`.
72 """
73 # Split into lines skipping empty ones.
74 lines = [line.strip() for line in adb_devices_output.split('\n')
75 if line.strip()]
76
77 if _ADB_DEVICES_HEADER not in lines:
78 return None
79
80 # The header can be preceeded by output informing of adb server being spawned,
81 # but all non-empty lines after the header describe connected devices.
82 device_specs = lines[lines.index(_ADB_DEVICES_HEADER) + 1:]
83 split_specs = [spec.split() for spec in device_specs]
84 return {split_spec[0]: split_spec[1] for split_spec in split_specs
85 if len(split_spec) == 2}
86
66 87
67 class AndroidShell(Shell): 88 class AndroidShell(Shell):
68 """Wrapper around Mojo shell running on an Android device. 89 """Wrapper around Mojo shell running on an Android device.
69 90
70 Args: 91 Args:
71 adb_path: Path to adb, optional if adb is in PATH. 92 adb_path: Path to adb, optional if adb is in PATH.
72 target_device: Device to run on, if multiple devices are connected. 93 target_device: Device to run on, if multiple devices are connected.
73 logcat_tags: Comma-separated list of additional logcat tags to use. 94 logcat_tags: Comma-separated list of additional logcat tags to use.
74 """ 95 """
75 96
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 device is available. Otherwise, it checks that there is exactly one 227 device is available. Otherwise, it checks that there is exactly one
207 available device. 228 available device.
208 229
209 Returns: 230 Returns:
210 A tuple of (result, msg). |result| is True iff if the device is correctly 231 A tuple of (result, msg). |result| is True iff if the device is correctly
211 configured and False otherwise. |msg| is the reason for failure if 232 configured and False otherwise. |msg| is the reason for failure if
212 |result| is False and None otherwise. 233 |result| is False and None otherwise.
213 """ 234 """
214 adb_devices_output = subprocess.check_output( 235 adb_devices_output = subprocess.check_output(
215 self._adb_command(['devices'])) 236 self._adb_command(['devices']))
216 # Skip the header line, strip empty lines at the end. 237 devices = parse_adb_devices_output(adb_devices_output)
217 device_list = [line.strip() for line in adb_devices_output.split('\n')[1:] 238
218 if line.strip()] 239 if not devices:
240 return False, 'No devices connected.'
219 241
220 if self.target_device: 242 if self.target_device:
221 if any([line.startswith(self.target_device) and 243 if (self.target_device in devices and
222 line.endswith('device') for line in device_list]): 244 devices[self.target_device] == 'device'):
223 return True, None 245 return True, None
224 else: 246 else:
225 return False, 'Cannot connect to the selected device.' 247 return False, ('Cannot connect to the selected device, status: ' +
248 devices[self.target_device])
226 249
227 if len(device_list) > 1: 250 if len(devices) > 1:
228 return False, ('More than one device connected and target device not ' 251 return False, ('More than one device connected and target device not '
229 'specified.') 252 'specified.')
230 253
231 if not len(device_list): 254 if not devices.itervalues().next() == 'device':
232 return False, 'No devices connected.'
233
234 if not device_list[0].endswith('device'):
235 return False, 'Connected device is not available.' 255 return False, 'Connected device is not available.'
236 256
237 if require_root and not self._run_adb_as_root(): 257 if require_root and not self._run_adb_as_root():
238 return False, 'Cannot run on an unrooted device.' 258 return False, 'Cannot run on an unrooted device.'
239 259
240 return True, None 260 return True, None
241 261
242 def install_apk(self, shell_apk_path): 262 def install_apk(self, shell_apk_path):
243 """Installs the apk on the device. 263 """Installs the apk on the device.
244 264
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 Results.output = rf.read() 441 Results.output = rf.read()
422 442
423 run_thread = threading.Thread(target=do_run) 443 run_thread = threading.Thread(target=do_run)
424 run_thread.start() 444 run_thread.start()
425 run_thread.join(timeout) 445 run_thread.join(timeout)
426 446
427 if run_thread.is_alive(): 447 if run_thread.is_alive():
428 self.stop_shell() 448 self.stop_shell()
429 return None, Results.output, True 449 return None, Results.output, True
430 return None, Results.output, False 450 return None, Results.output, False
OLDNEW
« no previous file with comments | « no previous file | mojo/devtools/common/devtoolslib/android_shell_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698