1#!/usr/bin/env python 2 3# This Source Code Form is subject to the terms of the Mozilla Public 4# License, v. 2.0. If a copy of the MPL was not distributed with this 5# file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7from __future__ import absolute_import 8 9import os 10 11from mozdevice import ADBDevice 12 13from logger.logger import RaptorLogger 14from performance_tuning import tune_performance 15from perftest import PerftestAndroid 16 17from .base import Browsertime 18 19LOG = RaptorLogger(component="raptor-browsertime-android") 20 21 22class BrowsertimeAndroid(PerftestAndroid, Browsertime): 23 """Android setup and configuration for browsertime 24 25 When running raptor-browsertime tests on android, we create the profile (and set the proxy 26 prefs in the profile that is using playback) but we don't need to copy it onto the device 27 because geckodriver takes care of that. 28 We tell browsertime to use our profile (we pass it in with the firefox.profileTemplate arg); 29 browsertime creates a copy of that and passes that into geckodriver. Geckodriver then takes 30 the profile and copies it onto the mobile device's test root for us; and then it even writes 31 the geckoview app config.yaml file onto the device, which points the app to the profile on 32 the device's test root. 33 Therefore, raptor doesn't have to copy the profile onto the scard (and create the config.yaml) 34 file ourselves. Also note when using playback, the nss certificate db is created as usual when 35 mitmproxy is started (and saved in the profile) so it is already included in the profile that 36 browsertime/geckodriver copies onto the device. 37 """ 38 39 def __init__(self, app, binary, activity=None, intent=None, **kwargs): 40 super(BrowsertimeAndroid, self).__init__( 41 app, binary, profile_class="firefox", **kwargs 42 ) 43 44 self.config.update({"activity": activity, "intent": intent}) 45 self.remote_test_root = "/data/local/tmp/tests/raptor" 46 self.remote_profile = os.path.join(self.remote_test_root, "profile") 47 48 @property 49 def browsertime_args(self): 50 if self.config['app'] == 'chrome-m': 51 args_list = [ 52 '--browser', 'chrome', 53 '--android', 54 ] 55 else: 56 args_list = [ 57 "--browser", "firefox", 58 "--android", 59 # Work around a `selenium-webdriver` issue where Browsertime 60 # fails to find a Firefox binary even though we're going to 61 # actually do things on an Android device. 62 "--firefox.binaryPath", self.browsertime_node, 63 "--firefox.android.package", self.config["binary"], 64 "--firefox.android.activity", self.config["activity"], 65 ] 66 67 # if running on Fenix we must add the intent as we use a special non-default one there 68 if self.config["app"] == "fenix" and self.config.get("intent") is not None: 69 args_list.extend(["--firefox.android.intentArgument=-a"]) 70 args_list.extend( 71 ["--firefox.android.intentArgument", self.config["intent"]] 72 ) 73 args_list.extend(["--firefox.android.intentArgument=-d"]) 74 args_list.extend(["--firefox.android.intentArgument", str("about:blank")]) 75 76 return args_list 77 78 def setup_chrome_args(self, test): 79 chrome_args = ["--use-mock-keychain", "--no-default-browser-check", "--no-first-run"] 80 81 if test.get("playback", False): 82 pb_args = [ 83 "--proxy-server=%s:%d" % (self.playback.host, self.playback.port), 84 "--proxy-bypass-list=localhost;127.0.0.1", 85 "--ignore-certificate-errors", 86 ] 87 88 if not self.is_localhost: 89 pb_args[0] = pb_args[0].replace("127.0.0.1", self.config["host"]) 90 91 chrome_args.extend(pb_args) 92 93 if self.debug_mode: 94 chrome_args.extend(["--auto-open-devtools-for-tabs"]) 95 96 args_list = [] 97 for arg in chrome_args: 98 args_list.extend(["--chrome.args=" + str(arg.replace("'", '"'))]) 99 100 return args_list 101 102 def build_browser_profile(self): 103 super(BrowsertimeAndroid, self).build_browser_profile() 104 105 # Merge in the Android profile. 106 path = os.path.join(self.profile_data_dir, "raptor-android") 107 LOG.info("Merging profile: {}".format(path)) 108 self.profile.merge(path) 109 self.profile.set_preferences( 110 {"browser.tabs.remote.autostart": self.config["e10s"]} 111 ) 112 113 # There's no great way to have "after" advice in Python, so we do this 114 # in super and then again here since the profile merging re-introduces 115 # the "#MozRunner" delimiters. 116 self.remove_mozprofile_delimiters_from_profile() 117 118 def setup_adb_device(self): 119 if self.device is None: 120 self.device = ADBDevice(verbose=True) 121 if not self.config.get("disable_perf_tuning", False): 122 tune_performance(self.device, log=LOG) 123 124 self.clear_app_data() 125 self.set_debug_app_flag() 126 127 def run_test_setup(self, test): 128 super(BrowsertimeAndroid, self).run_test_setup(test) 129 130 self.set_reverse_ports() 131 132 if self.playback: 133 self.turn_on_android_app_proxy() 134 self.remove_mozprofile_delimiters_from_profile() 135 136 def run_tests(self, tests, test_names): 137 self.setup_adb_device() 138 139 if self.config['app'] == "chrome-m": 140 # Make sure that chrome is enabled on the device 141 self.device.shell_output("pm enable com.android.chrome", root=True) 142 143 return super(BrowsertimeAndroid, self).run_tests(tests, test_names) 144 145 def run_test_teardown(self, test): 146 LOG.info("removing reverse socket connections") 147 self.device.remove_socket_connections("reverse") 148 149 super(BrowsertimeAndroid, self).run_test_teardown(test) 150