Chromium Code Reviews| Index: tools/telemetry/telemetry/user_story/android/shared_app_state.py |
| diff --git a/tools/telemetry/telemetry/user_story/android/shared_app_state.py b/tools/telemetry/telemetry/user_story/android/shared_app_state.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3b36aa00f42c0f5604f25daceae41dca4d2fc3e6 |
| --- /dev/null |
| +++ b/tools/telemetry/telemetry/user_story/android/shared_app_state.py |
| @@ -0,0 +1,174 @@ |
| +# Copyright 2014 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 re |
| +import subprocess |
| +import sys |
| + |
| +from telemetry.core import android_app |
| +from telemetry.core import exceptions |
| +from telemetry.core import platform |
| +from telemetry.core import util |
| +from telemetry.core import wpr_modes |
| +from telemetry.core.backends import adb_commands |
| +from telemetry.core.backends import android_app_backend |
| +from telemetry.core.platform import android_device |
| +from telemetry.user_story import shared_user_story_state |
| +from telemetry.web_perf import timeline_based_measurement |
| + |
| +try: |
| + import psutil # pylint: disable=import-error |
| +except ImportError: |
| + psutil = None |
| + |
| + |
| +class SharedAppState(shared_user_story_state.SharedUserStoryState): |
| + def __init__(self, test, finder_options, user_story_set): |
| + super(SharedAppState, self).__init__(test, finder_options, user_story_set) |
| + # SharedAppState only supports TimelineBasedMeasurement (TBM). |
| + # TODO(slamm): This SharedAppState does not yet interact with TBM yet |
| + # because TBM still has browser based logic. |
| + assert isinstance(test, timeline_based_measurement.TimelineBasedMeasurement) |
| + self._finder_options = finder_options |
| + self._android_app = None |
| + self._current_user_story = None |
| + self._platform = GetPlatform(finder_options) |
| + assert self._platform, 'Unable to create android platform.' |
| + |
| + @property |
| + def platform(self): |
| + return self._platform |
| + |
| + @property |
| + def _platform_backend(self): |
|
nednguyen
2014/12/05 20:15:22
This is a hack. If there is no plan to fix this in
slamm
2014/12/06 00:40:00
Done.
slamm
2014/12/06 00:40:00
Done.
|
| + return self._platform._platform_backend |
| + |
| + def _PrepareWpr(self, network_controller, archive_path, |
| + make_javascript_deterministic=True): |
| + browser_options = self._finder_options.browser_options |
| + if self._finder_options.use_live_sites: |
| + browser_options.wpr_mode = wpr_modes.WPR_OFF |
| + elif browser_options.wpr_mode != wpr_modes.WPR_RECORD: |
| + browser_options.wpr_mode = ( |
| + wpr_modes.WPR_REPLAY |
| + if archive_path and os.path.isfile(archive_path) |
| + else wpr_modes.WPR_OFF) |
| + |
| + # Replay's life-cycle is tied to the browser. Start and Stop are handled by |
| + # platform_backend.DidCreateBrowser and platform_backend.WillCloseBrowser, |
| + # respectively. |
| + # TODO(slamm): Update life-cycle comment with https://crbug.com/424777 fix. |
| + wpr_mode = browser_options.wpr_mode |
| + network_controller.SetReplayArgs( |
| + archive_path, wpr_mode, browser_options.netsim, |
| + browser_options.extra_wpr_args, make_javascript_deterministic) |
| + |
| + def WillRunUserStory(self, user_story): |
| + assert not self._android_app |
| + self._current_user_story = user_story |
| + #self._PrepareWpr(self.platform.network_controller, user_story.archive_path) |
| + |
| + # TODO(chrishenry): Should this be moved to |
| + # SharedAndroidAppState.DidRunUserStory? |
| + self._platform_backend.DismissCrashDialogIfNeeded() |
| + |
| + start_intent = user_story.start_intent |
| + platform_backend = self.platform._platform_backend # pylint: disable=W0212 |
| + app_backend = android_app_backend.AndroidAppBackend( |
| + platform_backend, start_intent) |
| + self._android_app = android_app.AndroidApp(app_backend, platform_backend) |
| + |
| + def RunUserStory(self, results): |
| + # CHEAT HAXX0R!! |
| + self._current_user_story.Run() |
| + |
| + def DidRunUserStory(self, results): |
| + if self._android_app: |
| + self._android_app.Close() |
| + self._android_app = None |
| + |
| + def GetTestExpectationAndSkipValue(self, expectations): |
| + # TODO(chrishenry): Implement this properly. |
| + return 'pass', None |
| + |
| + def TearDownState(self, results): |
| + pass |
| + |
| + |
| +def GetPlatform(finder_options): |
| + """Finds all the desktop browsers available on this machine.""" |
| + if not CanFindDevices(): |
| + logging.info('No adb command found. ' + |
| + 'Will not try searching for Android browsers.') |
| + return None |
| + |
| + if finder_options.android_device: |
| + devices = [android_device.AndroidDevice( |
| + finder_options.android_device, |
| + enable_performance_mode=not finder_options.no_performance_mode)] |
| + else: |
| + devices = android_device.AndroidDevice.GetAllConnectedDevices() |
| + |
| + if len(devices) == 0: |
| + logging.info('No android devices found.') |
| + return None |
| + elif len(devices) > 1: |
| + logging.warn( |
| + 'Multiple devices attached. Please specify one of the following:\n' + |
| + '\n'.join([' --device=%s' % d.device_id for d in devices])) |
| + return None |
| + |
| + try: |
| + android_platform = platform.GetPlatformForDevice(devices[0]) |
| + except exceptions.PlatformError: |
| + return None |
| + |
| + # Host side workaround for crbug.com/268450 (adb instability). |
| + # The adb server has a race which is mitigated by binding to a single core. |
| + if psutil: |
| + for proc in psutil.process_iter(): |
| + try: |
| + if 'adb' in proc.name: |
| + if 'cpu_affinity' in dir(proc): |
| + proc.cpu_affinity([0]) # New versions of psutil. |
| + elif 'set_cpu_affinity' in dir(proc): |
| + proc.set_cpu_affinity([0]) # Older versions. |
| + else: |
| + logging.warn( |
| + 'Cannot set CPU affinity due to stale psutil version: %s', |
| + '.'.join(str(x) for x in psutil.version_info)) |
| + except (psutil.NoSuchProcess, psutil.AccessDenied): |
| + logging.warn('Failed to set adb process CPU affinity') |
| + |
| + return android_platform |
| + |
| + |
| +def CanFindDevices(): |
| + if not adb_commands.IsAndroidSupported(): |
| + logging.info('Android build commands unavailable on this machine. Have ' |
| + 'you installed Android build dependencies?') |
| + return False |
| + |
| + try: |
| + with open(os.devnull, 'w') as devnull: |
| + proc = subprocess.Popen( |
| + ['adb', 'devices'], |
| + stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=devnull) |
| + stdout, _ = proc.communicate() |
| + if re.search(re.escape('????????????\tno permissions'), stdout) != None: |
| + logging.warn('adb devices reported a permissions error. Consider ' |
| + 'restarting adb as root:') |
| + logging.warn(' adb kill-server') |
| + logging.warn(' sudo `which adb` devices\n\n') |
| + return True |
| + except OSError: |
| + platform_tools_path = os.path.join(util.GetChromiumSrcDir(), |
| + 'third_party', 'android_tools', 'sdk', 'platform-tools') |
| + if (sys.platform.startswith('linux') and |
| + os.path.exists(os.path.join(platform_tools_path, 'adb'))): |
| + os.environ['PATH'] = os.pathsep.join([platform_tools_path, |
| + os.environ['PATH']]) |
| + return True |
| + return False |