from telemetry.core import platform
from telemetry.core import util
from telemetry.core.backends import adb_commands
-from telemetry.util import cloud_storage
-from telemetry.util import path
+from telemetry.util import support_binaries
util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
try:
def Create(self, port_pairs):
if self._rndis_configurator:
- return AndroidRndisForwarder(self._adb, self.host_ip,
- self._rndis_configurator.device_iface,
+ return AndroidRndisForwarder(self._adb, self._rndis_configurator,
port_pairs)
return AndroidForwarder(self._adb, port_pairs)
def __init__(self, adb, port_pairs):
super(AndroidForwarder, self).__init__(port_pairs)
self._device = adb.device()
- forwarder.Forwarder.Map([p for p in port_pairs if p], self._device)
+ forwarder.Forwarder.Map([(p.remote_port, p.local_port)
+ for p in port_pairs if p], self._device)
+ self._port_pairs = forwarders.PortPairs(*[
+ forwarders.PortPair(
+ p.local_port,
+ forwarder.Forwarder.DevicePortForHostPort(p.local_port))
+ if p else None for p in port_pairs])
# TODO(tonyg): Verify that each port can connect to host.
def Close(self):
for port_pair in self._port_pairs:
if port_pair:
- forwarder.Forwarder.UnmapDevicePort(port_pair.local_port, self._device)
+ forwarder.Forwarder.UnmapDevicePort(port_pair.remote_port, self._device)
super(AndroidForwarder, self).Close()
class AndroidRndisForwarder(forwarders.Forwarder):
"""Forwards traffic using RNDIS. Assumes the device has root access."""
- def __init__(self, adb, host_ip, device_iface, port_pairs):
+ def __init__(self, adb, rndis_configurator, port_pairs):
super(AndroidRndisForwarder, self).__init__(port_pairs)
self._adb = adb
- self._device_iface = device_iface
- self._host_ip = host_ip
+ self._rndis_configurator = rndis_configurator
+ self._device_iface = rndis_configurator.device_iface
+ self._host_ip = rndis_configurator.host_ip
self._original_dns = None, None, None
self._RedirectPorts(port_pairs)
if port_pairs.dns:
self._OverrideDns()
+ self._OverrideDefaultGateway()
+ # Need to override routing policy again since call to setifdns
+ # sometimes resets policy table
+ self._rndis_configurator.OverrideRoutingPolicy()
# TODO(tonyg): Verify that each port can connect to host.
@property
return self._host_ip
def Close(self):
+ self._rndis_configurator.RestoreRoutingPolicy()
self._SetDns(*self._original_dns)
+ self._RestoreDefaultGateway()
super(AndroidRndisForwarder, self).Close()
def _RedirectPorts(self, port_pairs):
def _OverrideDns(self):
"""Overrides DNS on device to point at the host."""
self._original_dns = self._GetCurrentDns()
- if not self._original_dns[0]:
- # No default route. Install one via the host. This is needed because
- # getaddrinfo in bionic uses routes to determine AI_ADDRCONFIG.
- self._adb.RunShellCommand('route add default gw %s dev %s' %
- (self.host_ip, self._device_iface))
self._SetDns(self._device_iface, self.host_ip, self.host_ip)
def _SetDns(self, iface, dns1, dns2):
self._adb.device().SetProp('net.dnschange', int(dnschange) + 1)
# Since commit 8b47b3601f82f299bb8c135af0639b72b67230e6 to frameworks/base
# the net.dns1 properties have been replaced with explicit commands for netd
- self._adb.RunShellCommand('ndc netd resolver setifdns %s %s %s' %
+ self._adb.RunShellCommand('netd resolver setifdns %s %s %s' %
(iface, dns1, dns2))
# TODO(szym): if we know the package UID, we could setifaceforuidrange
- self._adb.RunShellCommand('ndc netd resolver setdefaultif %s' % iface)
+ self._adb.RunShellCommand('netd resolver setdefaultif %s' % iface)
def _GetCurrentDns(self):
"""Returns current gateway, dns1, and dns2."""
self._adb.device().GetProp('net.dns2'),
)
+ def _OverrideDefaultGateway(self):
+ """Force traffic to go through RNDIS interface.
+
+ Override any default gateway route. Without this traffic may go through
+ the wrong interface.
+
+ This introduces the risk that _RestoreDefaultGateway() is not called
+ (e.g. Telemetry crashes). A power cycle or "adb reboot" is a simple
+ workaround around in that case.
+ """
+ self._adb.RunShellCommand('route add default gw %s dev %s' %
+ (self.host_ip, self._device_iface))
+
+ def _RestoreDefaultGateway(self):
+ self._adb.RunShellCommand('netcfg %s down' % self._device_iface)
+
class AndroidRndisConfigurator(object):
"""Configures a linux host to connect to an android device via RNDIS.
self.device_iface = None
if platform.GetHostPlatform().GetOSName() == 'mac':
- self._InstallHorndis()
+ self._InstallHorndis(platform.GetHostPlatform().GetArchName())
assert self._IsRndisSupported(), 'Device does not support RNDIS.'
self._CheckConfigureNetwork()
def _WriteProtectedFile(self, file_path, contents):
subprocess.check_call(
- ['sudo', 'bash', '-c', 'echo -e "%s" > %s' % (contents, file_path)])
+ ['/usr/bin/sudo', 'bash', '-c',
+ 'echo -e "%s" > %s' % (contents, file_path)])
- def _InstallHorndis(self):
+ def _InstallHorndis(self, arch_name):
if 'HoRNDIS' in subprocess.check_output(['kextstat']):
return
logging.info('Installing HoRNDIS...')
- pkg_path = os.path.join(
- path.GetTelemetryDir(), 'bin', 'mac', 'HoRNDIS-rel5.pkg')
- cloud_storage.GetIfChanged(pkg_path, bucket=cloud_storage.PUBLIC_BUCKET)
+ pkg_path = support_binaries.FindPath('HoRNDIS-rel5.pkg', arch_name, 'mac')
subprocess.check_call(
- ['sudo', 'installer', '-pkg', pkg_path, '-target', '/'])
+ ['/usr/bin/sudo', 'installer', '-pkg', pkg_path, '-target', '/'])
def _DisableRndis(self):
self._device.SetProp('sys.usb.config', 'adb')
if 'Telemetry' not in subprocess.check_output(
['networksetup', '-listallnetworkservices']):
subprocess.check_call(
- ['sudo', 'networksetup',
+ ['/usr/bin/sudo', 'networksetup',
'-createnetworkservice', 'Telemetry', host_iface])
subprocess.check_call(
- ['sudo', 'networksetup',
+ ['/usr/bin/sudo', 'networksetup',
'-setmanual', 'Telemetry', '192.168.123.1', '255.255.255.0'])
elif platform.GetHostPlatform().GetOSName() == 'linux':
with open(self._NETWORK_INTERFACES) as f:
if not os.path.exists(interface_conf_file):
interface_conf_dir = os.path.dirname(interface_conf_file)
if not interface_conf_dir:
- subprocess.call(['sudo', '/bin/mkdir', interface_conf_dir])
- subprocess.call(['sudo', '/bin/chmod', '755', interface_conf_dir])
+ subprocess.call(['/usr/bin/sudo', '/bin/mkdir', interface_conf_dir])
+ subprocess.call(
+ ['/usr/bin/sudo', '/bin/chmod', '755', interface_conf_dir])
interface_conf = '\n'.join([
'# Added by Telemetry for RNDIS forwarding.',
- 'auto %s' % host_iface,
+ 'allow-hotplug %s' % host_iface,
'iface %s inet static' % host_iface,
' address 192.168.123.1',
' netmask 255.255.255.0',
])
self._WriteProtectedFile(interface_conf_file, interface_conf)
- subprocess.check_call(['sudo', '/etc/init.d/networking', 'restart'])
- if 'stop/waiting' not in subprocess.check_output(
- ['status', 'network-manager']):
- logging.info('Stopping network-manager...')
- subprocess.call(['sudo', 'stop', 'network-manager'])
-
+ subprocess.check_call(['/usr/bin/sudo', 'ifup', host_iface])
logging.info('Waiting for RNDIS connectivity...')
util.WaitFor(HasHostAddress, 10)
return subprocess.call(['ping', '-q', '-c1', '-W1', self._device_ip],
stdout=devnull) == 0
+ def OverrideRoutingPolicy(self):
+ """Override any routing policy that could prevent
+ packets from reaching the rndis interface
+ """
+ policies = self._device.RunShellCommand('ip rule')
+ if len(policies) > 1 and not ('lookup main' in policies[1]):
+ self._device.RunShellCommand('ip rule add prio 1 from all table main')
+ self._device.RunShellCommand('ip route flush cache')
+
+ def RestoreRoutingPolicy(self):
+ policies = self._device.RunShellCommand('ip rule')
+ if len(policies) > 1 and re.match("^1:.*lookup main", policies[1]):
+ self._device.RunShellCommand('ip rule del prio 1')
+ self._device.RunShellCommand('ip route flush cache')
+
def _CheckConfigureNetwork(self):
"""Enables RNDIS and configures it, retrying until we have connectivity."""
force = False
for _ in range(3):
device_iface, host_iface = self._CheckEnableRndis(force)
self._ConfigureNetwork(device_iface, host_iface)
+ self.OverrideRoutingPolicy()
if self._TestConnectivity():
return
force = True
+ self.RestoreRoutingPolicy()
raise Exception('No connectivity, giving up.')