Android: Add --wait-for-java-debugger to test_runner.py
I used this to debug test listing in the instrumentation test runner.
This is nicer that using set-debug-app separately, because it disables
all timeouts (or else the process gets killed as you're debugging).
Change-Id: I7cd58c747534b3b539afcc84fcbae48475c4d9c3
Reviewed-on: https://chromium-review.googlesource.com/693218
Commit-Queue: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: Yoland Yan <yolandyan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#506049}
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py
index c7fef4a2..1343924 100755
--- a/build/android/apk_operations.py
+++ b/build/android/apk_operations.py
@@ -81,7 +81,7 @@
def _LaunchUrl(devices, input_args, device_args_file, url, apk,
- wait_for_debugger):
+ wait_for_java_debugger):
if input_args and device_args_file is None:
raise Exception('This apk does not support any flags.')
if url:
@@ -92,8 +92,10 @@
def launch(device):
# Set debug app in order to enable reading command line flags on user
# builds.
- cmd = ['am', 'set-debug-app', '--persistent', apk.GetPackageName()]
- if wait_for_debugger:
+ cmd = ['am', 'set-debug-app', apk.GetPackageName()]
+ if wait_for_java_debugger:
+ # To wait for debugging on a non-primary process:
+ # am set-debug-app org.chromium.chrome:privileged_process0
cmd[-1:-1] = ['-w']
# Ignore error since it will fail if apk is not debuggable.
device.RunShellCommand(cmd, check_return=False)
@@ -844,13 +846,15 @@
all_devices_by_default = True
def _RegisterExtraArgs(self, group):
- group.add_argument('-w', '--wait-for-debugger', action='store_true',
- help='Pause execution until debugger attaches.')
+ group.add_argument('-w', '--wait-for-java-debugger', action='store_true',
+ help='Pause execution until debugger attaches. Applies '
+ 'only to the main process. To have renderers wait, '
+ 'use --args="--renderer-wait-for-java-debugger"')
group.add_argument('url', nargs='?', help='A URL to launch with.')
def Run(self):
_LaunchUrl(self.devices, self.args.args, self.args.command_line_flags_file,
- self.args.url, self.apk_helper, self.args.wait_for_debugger)
+ self.args.url, self.apk_helper, self.args.wait_for_java_debugger)
class _StopCommand(_Command):
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index 26fedbf..4de7c81 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -293,6 +293,7 @@
self._suite = args.suite_name[0]
self._symbolizer = stack_symbolizer.Symbolizer(None, False)
self._gs_test_artifacts_bucket = args.gs_test_artifacts_bucket
+ self._wait_for_java_debugger = args.wait_for_java_debugger
# GYP:
if args.executable_dist_dir:
@@ -327,6 +328,8 @@
self._extras[_EXTRA_SHARD_SIZE_LIMIT] = 1
self._extras[EXTRA_SHARD_NANO_TIMEOUT] = int(1e9 * self._shard_timeout)
self._shard_timeout = 10 * self._shard_timeout
+ if args.wait_for_java_debugger:
+ self._extras[EXTRA_SHARD_NANO_TIMEOUT] = int(1e15) # Forever
if not self._apk_helper and not self._exe_dist_dir:
error_func('Could not find apk or executable for %s' % self._suite)
@@ -469,6 +472,10 @@
def total_external_shards(self):
return self._total_external_shards
+ @property
+ def wait_for_java_debugger(self):
+ return self._wait_for_java_debugger
+
#override
def TestType(self):
return 'gtest'
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 1bae4a0..6f1d0389 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -145,6 +145,10 @@
self._trace_all = None
if hasattr(args, 'trace_all'):
self._trace_all = args.trace_all
+ self._wait_for_java_debugger = args.wait_for_java_debugger
+
+ if self._wait_for_java_debugger:
+ self._max_tries = 1
devil_chromium.Initialize(
output_directory=constants.GetOutDirectory(),
@@ -250,6 +254,10 @@
def trace_output(self):
return self._trace_output
+ @property
+ def wait_for_java_debugger(self):
+ return self._wait_for_java_debugger
+
#override
def TearDown(self):
if self.trace_output:
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py
index 22794a43..6d9ae3a 100644
--- a/build/android/pylib/local/device/local_device_gtest_run.py
+++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -118,6 +118,7 @@
self._suite = test_instance.suite
self._component = '%s/%s' % (self._package, self._runner)
self._extras = test_instance.extras
+ self._wait_for_java_debugger = test_instance.wait_for_java_debugger
def GetTestDataRoot(self, device):
# pylint: disable=no-self-use
@@ -169,6 +170,10 @@
device.adb, dir=device.GetExternalStoragePath(), suffix='.gtest_out')
extras[_EXTRA_STDOUT_FILE] = stdout_file.name
+ if self._wait_for_java_debugger:
+ cmd = ['am', 'set-debug-app', '-w', self._package]
+ device.RunShellCommand(cmd, check_return=True)
+
with command_line_file, test_list_file, stdout_file:
try:
device.StartInstrumentation(
@@ -370,9 +375,12 @@
@local_device_environment.handle_shard_failures_with(
on_failure=self._env.BlacklistDevice)
def list_tests(dev):
+ timeout = 30
+ if self._test_instance.wait_for_java_debugger:
+ timeout = None
raw_test_list = crash_handler.RetryOnSystemCrash(
lambda d: self._delegate.Run(
- None, d, flags='--gtest_list_tests', timeout=30),
+ None, d, flags='--gtest_list_tests', timeout=timeout),
device=dev)
tests = gtest_test_instance.ParseGTestListTests(raw_test_list)
if not tests:
@@ -420,6 +428,8 @@
# Run the test.
timeout = (self._test_instance.shard_timeout
* self.GetTool(device).GetTimeoutScale())
+ if self._test_instance.wait_for_java_debugger:
+ timeout = None
if self._test_instance.store_tombstones:
tombstones.ClearAllTombstones(device)
with device_temp_file.DeviceTempFile(
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index 2c781791f..94ff92b 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -202,15 +202,16 @@
def set_debug_app(dev):
# Set debug app in order to enable reading command line flags on user
# builds
- if self._test_instance.flags:
- if not self._test_instance.package_info:
- logging.error("Couldn't set debug app: no package info")
- elif not self._test_instance.package_info.package:
- logging.error("Couldn't set debug app: no package defined")
- else:
- dev.RunShellCommand(['am', 'set-debug-app', '--persistent',
- self._test_instance.package_info.package],
- check_return=True)
+ if not self._test_instance.package_info:
+ logging.error("Couldn't set debug app: no package info")
+ elif not self._test_instance.package_info.package:
+ logging.error("Couldn't set debug app: no package defined")
+ else:
+ cmd = ['am', 'set-debug-app', '--persistent']
+ if self._env.wait_for_java_debugger:
+ cmd.append('-w')
+ cmd.append(self._test_instance.package_info.package)
+ dev.RunShellCommand(cmd, check_return=True)
@trace_event.traced
def edit_shared_prefs(dev):
@@ -421,6 +422,8 @@
valgrind_tools.SetChromeTimeoutScale(
device, test_timeout_scale * self._test_instance.timeout_scale)
+ if self._env.wait_for_java_debugger:
+ timeout = None
logging.info('preparing to run %s: %s', test_display_name, test)
render_tests_device_output_dir = None
@@ -611,8 +614,11 @@
extras['log'] = 'true'
extras[_EXTRA_TEST_LIST] = dev_test_list_json.name
target = '%s/%s' % (test_package, junit4_runner_class)
+ kwargs = {}
+ if self._env.wait_for_java_debugger:
+ kwargs['timeout'] = None
test_list_run_output = dev.StartInstrumentation(
- target, extras=extras)
+ target, extras=extras, retries=0, **kwargs)
if any(test_list_run_output):
logging.error('Unexpected output while listing tests:')
for line in test_list_run_output:
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index ae2275c..edfa8c5c 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -334,6 +334,10 @@
'--test-apk-incremental-install-json',
type=os.path.realpath,
help='Path to install json for the test apk.')
+ parser.add_argument(
+ '-w', '--wait-for-java-debugger', action='store_true',
+ help='Wait for java debugger to attach before running any application '
+ 'code. Also disables test timeouts and sets retries=0.')
filter_group = parser.add_mutually_exclusive_group()
filter_group.add_argument(
@@ -481,6 +485,10 @@
'--ui-screenshot-directory',
dest='ui_screenshot_dir', type=os.path.realpath,
help='Destination for screenshots captured by the tests')
+ parser.add_argument(
+ '-w', '--wait-for-java-debugger', action='store_true',
+ help='Wait for java debugger to attach before running any application '
+ 'code. Also disables test timeouts and sets retries=0.')
# These arguments are suppressed from the help text because they should
# only ever be specified by an intermediate script.
diff --git a/docs/android_debugging_instructions.md b/docs/android_debugging_instructions.md
index 705b538..62fd19fe 100644
--- a/docs/android_debugging_instructions.md
+++ b/docs/android_debugging_instructions.md
@@ -106,8 +106,8 @@
## Waiting for Java Debugger on Early Startup
-* To debug early startup, pass `--wait-for-java-debugger` as a command line
- flag.
+* To debug early startup, pass `--wait-for-java-debugger` to the wrapper
+ scripts (works for both apk wrappers as well as test wrappers).
## Debugging C/C++