aboutsummaryrefslogtreecommitdiff
path: root/catapult/telemetry/telemetry/internal/platform/profiler/tcpdump_profiler.py
diff options
context:
space:
mode:
Diffstat (limited to 'catapult/telemetry/telemetry/internal/platform/profiler/tcpdump_profiler.py')
-rw-r--r--catapult/telemetry/telemetry/internal/platform/profiler/tcpdump_profiler.py131
1 files changed, 131 insertions, 0 deletions
diff --git a/catapult/telemetry/telemetry/internal/platform/profiler/tcpdump_profiler.py b/catapult/telemetry/telemetry/internal/platform/profiler/tcpdump_profiler.py
new file mode 100644
index 00000000..b5f508a1
--- /dev/null
+++ b/catapult/telemetry/telemetry/internal/platform/profiler/tcpdump_profiler.py
@@ -0,0 +1,131 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import signal
+import subprocess
+import sys
+import tempfile
+
+from telemetry.internal.platform import profiler
+from telemetry.internal.platform.profiler import android_prebuilt_profiler_helper
+
+_TCP_DUMP_BASE_OPTS = ['-i', 'any', '-p', '-s', '0', '-w']
+
+
+class _TCPDumpProfilerAndroid(object):
+ """An internal class to collect TCP dumps on android.
+
+ This profiler uses pre-built binaries from AOSP.
+ See more details in prebuilt/android/README.txt.
+ """
+
+ _DEVICE_DUMP_FILE = '/sdcard/tcpdump_profiles/capture.pcap'
+
+ def __init__(self, device, output_path):
+ self._device = device
+ self._output_path = output_path
+ self._device.RunShellCommand('mkdir -p ' +
+ os.path.dirname(self._DEVICE_DUMP_FILE))
+ self._proc = subprocess.Popen(
+ [self._device.adb.GetAdbPath(),
+ '-s', self._device.adb.GetDeviceSerial(),
+ 'shell', android_prebuilt_profiler_helper.GetDevicePath('tcpdump')] +
+ _TCP_DUMP_BASE_OPTS +
+ [self._DEVICE_DUMP_FILE])
+
+ def CollectProfile(self):
+ tcpdump_pid = self._device.GetPids('tcpdump')
+ if not tcpdump_pid or not 'tcpdump' in tcpdump_pid:
+ raise Exception('Unable to find TCPDump. Check your device is rooted '
+ 'and tcpdump is installed at ' +
+ android_prebuilt_profiler_helper.GetDevicePath('tcpdump'))
+ if len(tcpdump_pid['tcpdump']) > 1:
+ raise Exception(
+ 'At most one instance of process tcpdump expected but found pids: '
+ '%s' % tcpdump_pid)
+ tcpdump_pid = int(tcpdump_pid['tcpdump'][0])
+ self._device.RunShellCommand('kill -term ' + tcpdump_pid)
+ self._proc.terminate()
+ host_dump = os.path.join(self._output_path,
+ os.path.basename(self._DEVICE_DUMP_FILE))
+ try:
+ self._device.PullFile(self._DEVICE_DUMP_FILE, host_dump)
+ except:
+ logging.exception('New exception caused by DeviceUtils conversion')
+ raise
+ print 'TCP dump available at: %s ' % host_dump
+ print 'Use Wireshark to open it.'
+ return host_dump
+
+
+class _TCPDumpProfilerLinux(object):
+ """An internal class to collect TCP dumps on linux desktop."""
+
+ _DUMP_FILE = 'capture.pcap'
+
+ def __init__(self, output_path):
+ if not os.path.exists(output_path):
+ os.makedirs(output_path)
+ self._dump_file = os.path.join(output_path, self._DUMP_FILE)
+ self._tmp_output_file = tempfile.NamedTemporaryFile('w', 0)
+ try:
+ self._proc = subprocess.Popen(
+ ['tcpdump'] + _TCP_DUMP_BASE_OPTS + [self._dump_file],
+ stdout=self._tmp_output_file, stderr=subprocess.STDOUT)
+ except OSError as e:
+ raise Exception('Unable to execute TCPDump, please check your '
+ 'installation. ' + str(e))
+
+ def CollectProfile(self):
+ self._proc.send_signal(signal.SIGINT)
+ exit_code = self._proc.wait()
+ try:
+ if exit_code:
+ raise Exception(
+ 'tcpdump failed with exit code %d. Output:\n%s' %
+ (exit_code, self._GetStdOut()))
+ finally:
+ self._tmp_output_file.close()
+ print 'TCP dump available at: ', self._dump_file
+ print 'Use Wireshark to open it.'
+ return self._dump_file
+
+ def _GetStdOut(self):
+ self._tmp_output_file.flush()
+ try:
+ with open(self._tmp_output_file.name) as f:
+ return f.read()
+ except IOError:
+ return ''
+
+
+class TCPDumpProfiler(profiler.Profiler):
+ """A Factory to instantiate the platform-specific profiler."""
+ def __init__(self, browser_backend, platform_backend, output_path, state):
+ super(TCPDumpProfiler, self).__init__(
+ browser_backend, platform_backend, output_path, state)
+ if platform_backend.GetOSName() == 'android':
+ android_prebuilt_profiler_helper.InstallOnDevice(
+ browser_backend.device, 'tcpdump')
+ self._platform_profiler = _TCPDumpProfilerAndroid(
+ browser_backend.device, output_path)
+ else:
+ self._platform_profiler = _TCPDumpProfilerLinux(output_path)
+
+ @classmethod
+ def name(cls):
+ return 'tcpdump'
+
+ @classmethod
+ def is_supported(cls, browser_type):
+ if browser_type.startswith('cros'):
+ return False
+ if sys.platform.startswith('linux'):
+ return True
+ return browser_type.startswith('android')
+
+ def CollectProfile(self):
+ return self._platform_profiler.CollectProfile()