#!/usr/bin/env vpython3
#
# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Takes a netlog for the WebViews in a given application.
Developer guide:
https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/net-debugging.md
"""
from __future__ import print_function
import argparse
import logging
import os
import posixpath
import re
import sys
import time
sys.path.append(
os.path.join(
os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
# pylint: disable=wrong-import-position,import-error
import devil_chromium
from devil.android import device_errors
from devil.android import flag_changer
from devil.android import device_utils
from devil.android.tools import script_common
from devil.utils import logging_common
WEBVIEW_COMMAND_LINE = 'webview-command-line'
def _WaitUntilCtrlC():
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print() # print a new line after the "^C" the user typed to the console
def CheckAppNotRunning(device, package_name, force):
is_running = bool(device.GetApplicationPids(package_name))
if is_running:
msg = ('Netlog requires setting commandline flags, which only works if the '
'application ({}) is not already running. Please kill the app and '
'restart the script.'.format(
package_name))
if force:
logging.warning(msg)
else:
# Extend the sentence to mention the user can skip the check.
msg = re.sub(r'\.$', ', or pass --force to ignore this check.', msg)
raise RuntimeError(msg)
def main():
parser = argparse.ArgumentParser(description="""
Configures WebView to start recording a netlog. This script chooses a suitable
netlog filename for the application, and will pull the netlog off the device
when the user terminates the script (with ctrl-C). For a more complete usage
guide, open your web browser to:
https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/net-debugging.md
""")
parser.add_argument(
'--package',
required=True,
type=str,
help='Package name of the application you intend to use.')
parser.add_argument(
'--force',
default=False,
action='store_true',
help='Suppress user checks.')
script_common.AddEnvironmentArguments(parser)
script_common.AddDeviceArguments(parser)
logging_common.AddLoggingArguments(parser)
args = parser.parse_args()
logging_common.InitializeLogging(args)
devil_chromium.Initialize(adb_path=args.adb_path)
# Only use a single device, for the sake of simplicity (of implementation and
# user experience).
devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices)
device = devices[0]
if len(devices) > 1:
raise device_errors.MultipleDevicesError(devices)
if device.build_type == 'user':
device_setup_url = ('https://chromium.googlesource.com/chromium/src/+/HEAD/'
'android_webview/docs/device-setup.md')
raise RuntimeError('It appears your device is a "user" build. We only '
'support capturing netlog on userdebug/eng builds. See '
'{} to configure a development device or set up an '
'emulator.'.format(device_setup_url))
package_name = args.package
device_netlog_file_name = 'netlog.json'
device_netlog_path = posixpath.join(
device.GetApplicationDataDirectory(package_name), 'app_webview',
device_netlog_file_name)
CheckAppNotRunning(device, package_name, args.force)
# Append to the existing flags, to allow users to experiment with other
# features/flags enabled. The CustomCommandLineFlags will restore the original
# flag state after the user presses 'ctrl-C'.
changer = flag_changer.FlagChanger(device, WEBVIEW_COMMAND_LINE)
new_flags = changer.GetCurrentFlags()
new_flags.append('--log-net-log={}'.format(device_netlog_path))
logging.info('Running with flags %r', new_flags)
with flag_changer.CustomCommandLineFlags(device, WEBVIEW_COMMAND_LINE,
new_flags):
print('Netlog will start recording as soon as app starts up. Press ctrl-C '
'to stop recording.')
_WaitUntilCtrlC()
host_netlog_path = 'netlog.json'
print('Pulling netlog to "%s"' % host_netlog_path)
# The netlog file will be under the app's uid, which the default shell doesn't
# have permission to read (but root does). Prefer this to EnableRoot(), which
# restarts the adb daemon.
if device.PathExists(device_netlog_path, as_root=True):
device.PullFile(device_netlog_path, host_netlog_path, as_root=True)
device.RemovePath(device_netlog_path, as_root=True)
else:
raise RuntimeError(
'Unable to find a netlog file in the "{}" app data directory. '
'Did you restart and run the app?'.format(package_name))
if __name__ == '__main__':
main()