Chromium Code Reviews| Index: tools/telemetry/telemetry/core/platform/win_platform_backend.py |
| diff --git a/tools/telemetry/telemetry/core/platform/win_platform_backend.py b/tools/telemetry/telemetry/core/platform/win_platform_backend.py |
| index 6e91b3a91beae84d4966a64eca143a4c9afeb465..f71b156361e7f83ca9f2ac771f5e744da6b87ffa 100644 |
| --- a/tools/telemetry/telemetry/core/platform/win_platform_backend.py |
| +++ b/tools/telemetry/telemetry/core/platform/win_platform_backend.py |
| @@ -5,16 +5,24 @@ |
| import collections |
| import contextlib |
| import ctypes |
| +import os |
| import platform |
| import re |
| +import socket |
| +import struct |
| import subprocess |
| +import sys |
| import time |
| +import zipfile |
| from telemetry import decorators |
| from telemetry.core import exceptions |
| +from telemetry.core import util |
| from telemetry.core.platform import desktop_platform_backend |
| from telemetry.core.platform import platform_backend |
| from telemetry.core.platform.power_monitor import msr_power_monitor |
| +from telemetry.util import cloud_storage |
| +from telemetry.util import path |
| try: |
| import pywintypes # pylint: disable=F0401 |
| @@ -34,6 +42,34 @@ except ImportError: |
| win32security = None |
| +def _InstallWinRing0(): |
| + """WinRing0 is used for reading MSRs.""" |
| + executable_dir = os.path.dirname(sys.executable) |
| + |
| + python_is_64_bit = sys.maxsize > 2 ** 32 |
| + dll_file_name = 'WinRing0x64.dll' if python_is_64_bit else 'WinRing0.dll' |
| + dll_path = os.path.join(executable_dir, dll_file_name) |
| + |
| + os_is_64_bit = 'PROGRAMFILES(X86)' in os.environ |
| + driver_file_name = 'WinRing0x64.sys' if os_is_64_bit else 'WinRing0.sys' |
| + driver_path = os.path.join(executable_dir, driver_file_name) |
| + |
| + # Check for WinRing0 and download if needed. |
| + if not (os.path.exists(dll_path) and os.path.exists(driver_path)): |
| + win_binary_dir = os.path.join(path.GetTelemetryDir(), 'bin', 'win') |
| + zip_path = os.path.join(win_binary_dir, 'winring0.zip') |
| + cloud_storage.GetIfChanged(zip_path, bucket=cloud_storage.PUBLIC_BUCKET) |
| + try: |
| + with zipfile.ZipFile(zip_path, 'r') as zip_file: |
| + # Install DLL. |
| + if not os.path.exists(dll_path): |
| + zip_file.extract(dll_file_name, executable_dir) |
| + # Install kernel driver. |
| + if not os.path.exists(driver_path): |
| + zip_file.extract(driver_file_name, executable_dir) |
| + finally: |
| + os.remove(zip_path) |
| + |
| def IsCurrentProcessElevated(): |
| handle = win32process.GetCurrentProcess() |
| @@ -46,8 +82,26 @@ def IsCurrentProcessElevated(): |
| class WinPlatformBackend(desktop_platform_backend.DesktopPlatformBackend): |
| def __init__(self): |
| super(WinPlatformBackend, self).__init__() |
| + self._msr_server_handle = None |
| + self._msr_server_port = None |
| self._power_monitor = msr_power_monitor.MsrPowerMonitor(self) |
| + def __del__(self): |
| + self.close() |
| + |
| + def close(self): |
| + self.CloseMsrServer() |
| + |
| + def CloseMsrServer(self): |
| + if not self._msr_server_handle: |
| + return |
| + |
| + exit_code = win32process.GetExitCodeProcess(self._msr_server_handle) |
| + if exit_code == win32con.STILL_ACTIVE: |
| + win32process.TerminateProcess(self._msr_server_handle, 0) |
| + self._msr_server_handle = None |
| + self._msr_server_port = None |
| + |
| # pylint: disable=W0613 |
| def StartRawDisplayFrameRateMeasurement(self): |
| raise NotImplementedError() |
| @@ -259,3 +313,34 @@ class WinPlatformBackend(desktop_platform_backend.DesktopPlatformBackend): |
| def StopMonitoringPower(self): |
| return self._power_monitor.StopMonitoringPower() |
| + |
| + def _StartMsrServerIfNeeded(self): |
| + if self._msr_server_handle: |
| + return |
| + |
| + _InstallWinRing0() |
|
tonyg
2014/09/18 00:21:46
Since the server must be privileged, should we do
dtu
2014/09/18 05:22:29
Yes, but I felt it to be cleaner for the server to
|
| + self._msr_server_port = util.GetUnreservedAvailableLocalPort() |
| + parameters = ( |
| + os.path.join(os.path.dirname(__file__), 'msr_server_win.py'), |
| + str(self._msr_server_port), |
| + ) |
| + self._msr_server_handle = self.LaunchApplication( |
| + sys.executable, parameters, elevate_privilege=True) |
| + # Wait for server to start. connect has a default timeout of 1 second. |
| + try: |
| + socket.create_connection(('127.0.0.1', self._msr_server_port)).close() |
|
tonyg
2014/09/18 00:21:46
Server starting/stopping seems like it should be s
dtu
2014/09/18 05:22:29
I'm not sure if all platforms will use a server li
|
| + except socket.error: |
| + self.CloseMsrServer() |
| + |
| + def ReadMsr(self, msr_number): |
| + self._StartMsrServerIfNeeded() |
| + if not self._msr_server_handle: |
| + raise OSError('Unable to start MSR server.') |
| + |
| + sock = socket.create_connection(('127.0.0.1', self._msr_server_port), 0.1) |
| + try: |
| + sock.sendall(struct.pack('I', msr_number)) |
| + response = sock.recv(8) |
| + finally: |
| + sock.close() |
| + return struct.unpack('Q', response)[0] |