blob: cacb8fd109835c60f49edb5be9b9bf8eb5dbffb8 [file] [log] [blame]
'''Module that contains the base class TestBaseRemote'''
from __future__ import absolute_import
import os
import re
from .test_base import TestBase
from . import util_log
class TestBaseRemote(TestBase):
'''Base class for all tests that connect to a remote device.
Provides common functionality to set up the connection and tear it down.
'''
def __init__(self, device_port, device, timer, *args, **kwargs):
super(TestBaseRemote, self).__init__(device_port, device, timer, *args, **kwargs)
# port used by lldb-server on the device.
self._device_port = device_port
self._platform = None
# id of the device that adb will communicate with.
self._device = device
def set_src_map(self, file_name, new_src_path):
'''Call lldb to set the source mapping of a given file.
Set lldb's source mapping of a given file to a given path. This can be
used to make the test suite independent of where an APK was compiled.
Args:
file_name: String, which is the name of the file whose mapping is
to be changed
new_src_path: String which is the new absolute path to the source
file.
'''
line_table = self.do_command('target modules dump line-table '
+ file_name)
lines = line_table.split('\n')
if 'Line table for' not in lines[0]:
raise self.TestFail('Could not determine source path of '
+ file_name)
# Expecting output like:
# (lldb) target modules dump line-table scalars.rs
# Line table for /home/jenkins/workspace/grd-aosp-parameterised-build/
# merge_151216/frameworks/rs/tests/lldb/java/BranchingFunCalls/src/rs/
# frameworks/rs/tests/lldb/java/BranchingFunCalls/src/rs/scalars.rs in
# `librs.scalars.so
# 0xb30f2374: /home/jenkins/workspace/grd-aosp-parameterised-build/
# merge_151216/frameworks/rs/tests/lldb/java/BranchingFunCalls/src/rs/
# scalars.rs:46
# ...
# For some reason the first line contains a mangled path?
old_path = re.findall(r"[^ :]+", lines[1])[1]
old_dir = os.path.dirname(old_path)
self.try_command('settings set target.source-map %s %s'
% (old_dir, new_src_path), [''])
def post_run(self):
'''Clean up after execution.'''
if self._platform:
self._platform.DisconnectRemote()
def _connect_to_platform(self, lldb_module, dbg, remote_pid):
'''Connect to an lldb platform that has been started elsewhere.
Args:
lldb_module: A handle to the lldb module.
dbg: The instance of the SBDebugger that should connect to the
server.
remote_pid: The integer that is the process id of the binary that
the debugger should attach to.
Returns:
True if the debugger successfully attached to the server and
process.
'''
# pylint: disable=too-many-return-statements
remote_pid = str(remote_pid)
log = util_log.get_logger()
err1 = dbg.SetCurrentPlatform('remote-android')
if err1.Fail():
log.fatal(err1.GetCString())
return False
self._platform = dbg.GetSelectedPlatform()
if not self._platform:
return False
connect_string = \
'adb://{0}:{1}'.format(self._device, self._device_port)
opts = lldb_module.SBPlatformConnectOptions(connect_string)
for _ in range(2):
err2 = self._platform.ConnectRemote(opts)
if err2.Fail():
log.error(err2.GetCString())
if 'Connection refused' in err2.GetCString():
log.warning('Connection to lldb server was refused. '
'Trying again.')
else:
# Unknown error. Don't try again.
return False
else:
# Success
break
else:
log.fatal('Not trying again, maximum retries exceeded.')
return False
target = dbg.CreateTarget(None)
if not target:
return False
dbg.SetSelectedTarget(target)
listener = lldb_module.SBListener()
err3 = lldb_module.SBError()
process = target.AttachToProcessWithID(listener, int(remote_pid), err3)
if err3.Fail() or not process:
log.fatal(err3.GetCString())
return False
return True
def run(self, dbg, remote_pid, lldb):
'''Execute the actual testsuite.
Args:
dbg: The instance of the SBDebugger that is used to test commands.
remote_pid: The integer that is the process id of the binary that
the debugger is attached to.
lldb: A handle to the lldb module.
Returns: list of (test, failure) tuples.
'''
assert dbg
assert remote_pid
assert lldb
self._lldb = lldb
self.assert_true(self._connect_to_platform(lldb, dbg, remote_pid))
self._ci = dbg.GetCommandInterpreter()
assert self._ci
self.assert_true(self._ci.IsValid())
self.assert_true(self._ci.HasCommands())
return super(TestBaseRemote, self).run(dbg, remote_pid, lldb)