record_netlog.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/usr/bin/env vpython3
  2. #
  3. # Copyright 2019 The Chromium Authors. All rights reserved.
  4. # Use of this source code is governed by a BSD-style license that can be
  5. # found in the LICENSE file.
  6. """Takes a netlog for the WebViews in a given application.
  7. Developer guide:
  8. https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/net-debugging.md
  9. """
  10. from __future__ import print_function
  11. import argparse
  12. import logging
  13. import os
  14. import posixpath
  15. import re
  16. import sys
  17. import time
  18. sys.path.append(
  19. os.path.join(
  20. os.path.dirname(__file__), os.pardir, os.pardir, 'build', 'android'))
  21. # pylint: disable=wrong-import-position,import-error
  22. import devil_chromium
  23. from devil.android import device_errors
  24. from devil.android import flag_changer
  25. from devil.android import device_utils
  26. from devil.android.tools import script_common
  27. from devil.utils import logging_common
  28. WEBVIEW_COMMAND_LINE = 'webview-command-line'
  29. def _WaitUntilCtrlC():
  30. try:
  31. while True:
  32. time.sleep(1)
  33. except KeyboardInterrupt:
  34. print() # print a new line after the "^C" the user typed to the console
  35. def CheckAppNotRunning(device, package_name, force):
  36. is_running = bool(device.GetApplicationPids(package_name))
  37. if is_running:
  38. msg = ('Netlog requires setting commandline flags, which only works if the '
  39. 'application ({}) is not already running. Please kill the app and '
  40. 'restart the script.'.format(
  41. package_name))
  42. if force:
  43. logging.warning(msg)
  44. else:
  45. # Extend the sentence to mention the user can skip the check.
  46. msg = re.sub(r'\.$', ', or pass --force to ignore this check.', msg)
  47. raise RuntimeError(msg)
  48. def main():
  49. parser = argparse.ArgumentParser(description="""
  50. Configures WebView to start recording a netlog. This script chooses a suitable
  51. netlog filename for the application, and will pull the netlog off the device
  52. when the user terminates the script (with ctrl-C). For a more complete usage
  53. guide, open your web browser to:
  54. https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/net-debugging.md
  55. """)
  56. parser.add_argument(
  57. '--package',
  58. required=True,
  59. type=str,
  60. help='Package name of the application you intend to use.')
  61. parser.add_argument(
  62. '--force',
  63. default=False,
  64. action='store_true',
  65. help='Suppress user checks.')
  66. script_common.AddEnvironmentArguments(parser)
  67. script_common.AddDeviceArguments(parser)
  68. logging_common.AddLoggingArguments(parser)
  69. args = parser.parse_args()
  70. logging_common.InitializeLogging(args)
  71. devil_chromium.Initialize(adb_path=args.adb_path)
  72. # Only use a single device, for the sake of simplicity (of implementation and
  73. # user experience).
  74. devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices)
  75. device = devices[0]
  76. if len(devices) > 1:
  77. raise device_errors.MultipleDevicesError(devices)
  78. if device.build_type == 'user':
  79. device_setup_url = ('https://chromium.googlesource.com/chromium/src/+/HEAD/'
  80. 'android_webview/docs/device-setup.md')
  81. raise RuntimeError('It appears your device is a "user" build. We only '
  82. 'support capturing netlog on userdebug/eng builds. See '
  83. '{} to configure a development device or set up an '
  84. 'emulator.'.format(device_setup_url))
  85. package_name = args.package
  86. device_netlog_file_name = 'netlog.json'
  87. device_netlog_path = posixpath.join(
  88. device.GetApplicationDataDirectory(package_name), 'app_webview',
  89. device_netlog_file_name)
  90. CheckAppNotRunning(device, package_name, args.force)
  91. # Append to the existing flags, to allow users to experiment with other
  92. # features/flags enabled. The CustomCommandLineFlags will restore the original
  93. # flag state after the user presses 'ctrl-C'.
  94. changer = flag_changer.FlagChanger(device, WEBVIEW_COMMAND_LINE)
  95. new_flags = changer.GetCurrentFlags()
  96. new_flags.append('--log-net-log={}'.format(device_netlog_path))
  97. logging.info('Running with flags %r', new_flags)
  98. with flag_changer.CustomCommandLineFlags(device, WEBVIEW_COMMAND_LINE,
  99. new_flags):
  100. print('Netlog will start recording as soon as app starts up. Press ctrl-C '
  101. 'to stop recording.')
  102. _WaitUntilCtrlC()
  103. host_netlog_path = 'netlog.json'
  104. print('Pulling netlog to "%s"' % host_netlog_path)
  105. # The netlog file will be under the app's uid, which the default shell doesn't
  106. # have permission to read (but root does). Prefer this to EnableRoot(), which
  107. # restarts the adb daemon.
  108. if device.PathExists(device_netlog_path, as_root=True):
  109. device.PullFile(device_netlog_path, host_netlog_path, as_root=True)
  110. device.RemovePath(device_netlog_path, as_root=True)
  111. else:
  112. raise RuntimeError(
  113. 'Unable to find a netlog file in the "{}" app data directory. '
  114. 'Did you restart and run the app?'.format(package_name))
  115. if __name__ == '__main__':
  116. main()