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 atexit
6import logging
7import subprocess
8
9from telemetry.internal import forwarders
10
11try:
12  from devil.android import forwarder
13except ImportError:
14  forwarder = None
15
16
17class AndroidForwarderFactory(forwarders.ForwarderFactory):
18
19  def __init__(self, device):
20    super(AndroidForwarderFactory, self).__init__()
21    self._device = device
22
23  def Create(self, port_pairs):
24    try:
25      return AndroidForwarder(self._device, port_pairs)
26    except Exception:
27      try:
28        logging.warning('Failed to create forwarder. '
29                        'Currently forwarded connections:')
30        for line in self._device.adb.ForwardList().splitlines():
31          logging.warning('  %s', line)
32      except Exception:
33        logging.warning('Exception raised while listing forwarded connections.')
34
35      logging.warning('Device tcp sockets in use:')
36      try:
37        for line in self._device.ReadFile('/proc/net/tcp', as_root=True,
38                                          force_pull=True).splitlines():
39          logging.warning('  %s', line)
40      except Exception:
41        logging.warning('Exception raised while listing tcp sockets.')
42
43      logging.warning('Alive webpagereplay instances:')
44      try:
45        for line in subprocess.check_output(['ps', '-ef']).splitlines():
46          if 'webpagereplay' in line:
47            logging.warning('  %s', line)
48      except Exception:
49        logging.warning('Exception raised while listing WPR intances.')
50
51      raise
52
53
54class AndroidForwarder(forwarders.Forwarder):
55
56  def __init__(self, device, port_pairs):
57    super(AndroidForwarder, self).__init__(port_pairs)
58    self._device = device
59    forwarder.Forwarder.Map([(p.remote_port, p.local_port)
60                             for p in port_pairs if p], self._device)
61    self._port_pairs = forwarders.PortPairs(*[
62        forwarders.PortPair(
63            p.local_port,
64            forwarder.Forwarder.DevicePortForHostPort(p.local_port))
65        if p else None for p in port_pairs])
66    atexit.register(self.Close)
67    # TODO(tonyg): Verify that each port can connect to host.
68
69  def Close(self):
70    if self._forwarding:
71      for port_pair in self._port_pairs:
72        if port_pair:
73          forwarder.Forwarder.UnmapDevicePort(
74              port_pair.remote_port, self._device)
75      super(AndroidForwarder, self).Close()
76