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 |