diff --git a/wa/workloads/speedometer/LICENSE b/wa/workloads/speedometer/LICENSE
new file mode 100644
index 00000000..dcf7fb52
--- /dev/null
+++ b/wa/workloads/speedometer/LICENSE
@@ -0,0 +1,7 @@
+The speedometer_archive.tgz file is a tarball containing the following archives from WebKit:
+
+ the PerformanceTests/Speedometer directory state taken from https://github.com/WebKit/webkit as of:
+ commit 5f402692d5f3406527dc107b5d20cc47dac929e8 Tue Jul 14 14:06:17 2020 +0000
+
+WebKit is open source software with portions licensed under the LGPL and BSD
+licenses available at https://webkit.org/licensing-webkit/
diff --git a/wa/workloads/speedometer/__init__.py b/wa/workloads/speedometer/__init__.py
index 718fe603..27a7aa4f 100755
--- a/wa/workloads/speedometer/__init__.py
+++ b/wa/workloads/speedometer/__init__.py
@@ -12,57 +12,411 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+from collections import defaultdict
+from http.server import SimpleHTTPRequestHandler, HTTPServer
+import logging
import os
import re
+import subprocess
+import tarfile
+import tempfile
+import threading
+import time
+import uuid
-from wa import ApkUiautoWorkload, Parameter
-from wa.framework.exception import ValidationError, WorkloadError
-from wa.utils.types import list_of_strs
-from wa.utils.misc import unique
+from wa import Parameter, Workload, File
+from wa.framework.exception import WorkloadError
+from wa.utils.exec_control import once
+
+from devlib.utils.android import adb_command
-class Speedometer(ApkUiautoWorkload):
+class Speedometer(Workload):
- name = 'speedometer'
- package_names = ['com.android.chrome']
- regex = re.compile(r'Speedometer Score ([\d.]+)')
- versions = ['1.0', '2.0']
- description = '''
- A workload to execute the speedometer web based benchmark
+ name = "speedometer"
+ description = """
+ A workload to execute the speedometer 2.0 web based benchmark. Requires device to be rooted.
+ This workload will only with Android 9+ devices if connected via TCP, or Android 5+ if
+ connected via USB.
Test description:
- 1. Open chrome
- 2. Navigate to the speedometer website - http://browserbench.org/Speedometer/
- 3. Execute the benchmark
+ 1. Host a local copy of the Speedometer website, and make it visible to the device via ADB.
+ 2. Open chrome via an intent to access the local copy.
+ 3. Execute the benchmark - the copy has been modified to trigger the start of the benchmark.
+ 4. The benchmark will write to the browser's sandboxed local storage to signal the benchmark
+ has completed. This local storage is monitored by this workload.
- known working chrome version 80.0.3987.149
- '''
+ Known working chrome version 83.0.4103.106
+
+ To modify the archived speedometer workload:
+
+ 1. Run 'git clone https://github.com/WebKit/webkit'
+
+ 2. Copy PerformanceTests/Speedometer to a directory called document_root, renaming Speedometer to Speedometer2.0
+
+ 3. Modify document_root/Speedometer2.0/index.html:
+ 3a. Remove the 'defer' attribute from the ' to the very end of the
section.
+
+ 4. Modify document_root/Speedometer2.0/resources/main.js:
+ 4a. Add the listed code after this line:
+
+ document.getElementById('result-number').textContent = results.formattedMean;
+
+ Code to add:
+
+ if (location.search.length > 1) {
+ var parts = location.search.substring(1).split('&');
+ for (var i = 0; i < parts.length; i++) {
+ var keyValue = parts[i].split('=');
+ var key = keyValue[0];
+ var value = keyValue[1];
+ if (key === "reportEndId") {
+ window.localStorage.setItem('reportEndId', value);
+ }
+ }
+ }
+
+ 5. Run 'tar -cpzf speedometer_archive.tgz document_root'
+
+ 6. Copy the tarball into the workloads/speedometer directory
+
+ 7. If appropriate, update the commit info in the LICENSE file.
+ """
+ supported_platforms = ["android"]
+
+ package_names = ["org.chromium.chrome", "com.android.chrome"]
+ # This regex finds a single XML tag where property 1 and 2 are true:
+ # 1. contains the attribute text="XXX" or content-desc="XXX"
+ # 2. and exclusively either 2a or 2b is true:
+ # 2a. there exists a resource-id="result-number" to that attribute's left
+ # 2b. there exists a resource-id="result-number" to that attribute's right
+ # The regex stores the XXX value of that attribute in the named group 'value'.
+ #
+ # Just in case someone wants to learn something:
+ # If you use (?Pregex)? to match 'regex', and then afterwards you
+ # have (?(tag)A|B), then regex A will be used if the 'tag' group captured
+ # something and B will be used if nothing was captured. This is how we
+ # search for 'resource-id="result-number"' after the text/content-desc
+ # _only_ in the case we didn't see it before.
+ regex = re.compile(
+ '<[^>]*(?Presource-id="result-number")?[^>]*'
+ '(?:text|content-desc)="(?P\d+.\d+)"[^>]*'
+ '(?(Z)|resource-id="result-number")[^>]*\/>'
+ )
parameters = [
- Parameter('speedometer_version', allowed_values=versions, kind=str, default='2.0',
- description='''
- The speedometer version to be used.
- ''')
+ Parameter(
+ "chrome_package",
+ allowed_values=package_names,
+ kind=str,
+ default="com.android.chrome",
+ description="""
+ The app package for the browser that will be launched.
+ """,
+ ),
]
- requires_network = True
-
def __init__(self, target, **kwargs):
super(Speedometer, self).__init__(target, **kwargs)
- self.gui.timeout = 1500
- self.gui.uiauto_params['version'] = self.speedometer_version
+ self.target_file_was_seen = defaultdict(lambda: False)
+ self.ui_dump_loc = None
+
+ @once
+ def initialize(self, context):
+ super(Speedometer, self).initialize(context)
+ self.archive_server = ArchiveServer()
+ if not self.target.is_rooted:
+ raise WorkloadError(
+ "Device must be rooted for the speedometer workload currently"
+ )
+
+ if self.target.adb_server is not None:
+ raise WorkloadError(
+ "Workload does not support the adb_server parameter, due to the webpage "
+ "hosting mechanism."
+ )
+
+ # Temporary directory used for storing the Speedometer files, uiautomator
+ # dumps, and modified XML chrome config files.
+ self.temp_dir = tempfile.TemporaryDirectory()
+ self.document_root = os.path.join(self.temp_dir.name, "document_root")
+
+ # Host a copy of Speedometer locally
+ tarball = context.get_resource(File(self, "speedometer_archive.tgz"))
+ with tarfile.open(name=tarball) as handle:
+ handle.extractall(self.temp_dir.name)
+ self.archive_server.start(self.document_root, self.target)
+ self.webserver_port = self.archive_server.get_port()
+
+ self.speedometer_url = "http://localhost:{}/Speedometer2.0/index.html".format(
+ self.webserver_port
+ )
+
+ def setup(self, context):
+ super(Speedometer, self).setup(context)
+
+ # We are making sure we start with a 'fresh' browser - no other tabs,
+ # nothing in the page cache, etc.
+
+ # Clear the application's cache.
+ self.target.execute("pm clear {}".format(self.chrome_package), as_root=True)
+
+ # Launch the browser for the first time and then stop it. Since the
+ # cache has just been cleared, this forces it to recreate its
+ # preferences file, that we need to modify.
+ browser_launch_cmd = "am start -a android.intent.action.VIEW -d {} {}".format(
+ self.speedometer_url, self.chrome_package
+ )
+ self.target.execute(browser_launch_cmd)
+ time.sleep(1)
+ self.target.execute("am force-stop {}".format(self.chrome_package))
+ time.sleep(1)
+
+ # Pull the preferences file from the device, modify it, and push it
+ # back. This is done to bypass the 'first launch' screen of the
+ # browser we see after the cache is cleared.
+ self.preferences_xml = "{}_preferences.xml".format(self.chrome_package)
+
+ file_to_modify = "/data/data/{}/shared_prefs/{}".format(
+ self.chrome_package, self.preferences_xml
+ )
+
+ self.target.pull(file_to_modify, self.temp_dir.name, as_root=True)
+
+ with open(os.path.join(self.temp_dir.name, self.preferences_xml)) as read_fh:
+ lines = read_fh.readlines()
+
+ # Add additional elements for the preferences XML to the
+ # _second-last_ line
+ for line in [
+ '\n',
+ '\n',
+ '\n',
+ '\n',
+ ]:
+ lines.insert(len(lines) - 1, line)
+
+ with open(
+ os.path.join(self.temp_dir.name, self.preferences_xml + ".new"), "w",
+ ) as write_fh:
+ for line in lines:
+ write_fh.write(line)
+
+ # Make sure ownership of the original file is preserved.
+ user_owner, group_owner = self.target.execute(
+ "ls -l {}".format(file_to_modify), as_root=True,
+ ).split()[2:4]
+
+ self.target.push(
+ os.path.join(self.temp_dir.name, self.preferences_xml + ".new"),
+ file_to_modify,
+ as_root=True,
+ )
+
+ self.target.execute(
+ "chown {}.{} {}".format(user_owner, group_owner, file_to_modify),
+ as_root=True,
+ )
+
+ def run(self, context):
+ super(Speedometer, self).run(context)
+
+ # Generate a UUID to search for in the browser's local storage to find out
+ # when the workload has ended.
+ report_end_id = uuid.uuid4().hex
+ url_with_unique_id = "{}?reportEndId={}".format(
+ self.speedometer_url, report_end_id
+ )
+
+ browser_launch_cmd = "am start -a android.intent.action.VIEW -d '{}' {}".format(
+ url_with_unique_id, self.chrome_package
+ )
+ self.target.execute(browser_launch_cmd)
+
+ self.wait_for_benchmark_to_complete(report_end_id)
+
+ def target_file_was_created(self, f):
+ """Assume that once self.target.file_exists(f) returns True, it will
+ always be True from that point forward, so cache the response into the
+ self.target_file_was_seen dict."""
+ if not self.target_file_was_seen[f]:
+ self.target_file_was_seen[f] = self.target.file_exists(f)
+ return self.target_file_was_seen[f]
+
+ def wait_for_benchmark_to_complete(self, report_end_id):
+ local_storage = "/data/data/{}/app_chrome/Default/Local Storage/leveldb".format(
+ self.chrome_package
+ )
+
+ sleep_period_s = 5
+ find_period_s = 30
+ timeout_period_m = 15
+
+ iterations = 0
+ local_storage_seen = False
+ benchmark_complete = False
+ while not benchmark_complete:
+ if self.target_file_was_created(local_storage):
+ if (
+ iterations % (find_period_s // sleep_period_s) == 0 or
+ not local_storage_seen
+ ):
+ # There's a chance we don't see the localstorage file immediately, and there's a
+ # chance more of them could be created later, so check for those files every ~30
+ # seconds.
+ find_cmd = '{} find "{}" -iname "*.log"'.format(
+ self.target.busybox, local_storage
+ )
+ candidate_files = self.target.execute(find_cmd, as_root=True).split(
+ "\n"
+ )
+
+ local_storage_seen = True
+
+ for ls_file in candidate_files:
+ # Each local storage file is in a binary format. The busybox grep seems to
+ # print out the line '[KEY][VALUE]' for a match, rather than just reporting
+ # that 'binary file X matches', so just check the output for our generated ID.
+ grep_cmd = '{} grep {} "{}"'.format(
+ self.target.busybox, report_end_id, ls_file
+ )
+ output = self.target.execute(
+ grep_cmd, as_root=True, check_exit_code=False
+ )
+ if report_end_id in output:
+ benchmark_complete = True
+ break
+
+ iterations += 1
+
+ if iterations > ((timeout_period_m * 60) // sleep_period_s):
+ # We've been waiting 15 minutes for Speedometer to finish running - give up.
+ if not local_storage_seen:
+ raise WorkloadError(
+ "Speedometer did not complete within 15m - Local Storage wasn't found"
+ )
+ raise WorkloadError("Speedometer did not complete within 15 minutes.")
+
+ time.sleep(sleep_period_s)
+
+ def read_score(self):
+ self.target.execute(
+ "uiautomator dump {}".format(self.ui_dump_loc), as_root=True
+ )
+ self.target.pull(self.ui_dump_loc, self.temp_dir.name)
+
+ with open(os.path.join(self.temp_dir.name, "ui_dump.xml"), "rb") as fh:
+ dump = fh.read().decode("utf-8")
+ match = self.regex.search(dump)
+ result = None
+ if match:
+ result = float(match.group("value"))
+
+ return result
def update_output(self, context):
super(Speedometer, self).update_output(context)
- result = None
- logcat_file = context.get_artifact_path('logcat')
- with open(logcat_file, errors='replace') as fh:
- for line in fh:
- match = self.regex.search(line)
- if match:
- result = float(match.group(1))
- if result is not None:
- context.add_metric('Speedometer Score', result, 'Runs per minute', lower_is_better=False)
- else:
- raise WorkloadError("The Speedometer workload has failed. No score was obtainable.")
+ self.ui_dump_loc = os.path.join(self.target.working_directory, "ui_dump.xml")
+
+ score_read = False
+ iterations = 0
+ while not score_read:
+ score = self.read_score()
+
+ if score is not None:
+ context.add_metric(
+ "Speedometer Score", score, "Runs per minute", lower_is_better=False
+ )
+ score_read = True
+ else:
+ if iterations >= 10:
+ raise WorkloadError(
+ "The Speedometer workload has failed. No score was obtainable."
+ )
+ else:
+ # Sleep and retry...
+ time.sleep(2)
+ iterations += 1
+
+ def teardown(self, context):
+ super(Speedometer, self).teardown(context)
+
+ # The browser's processes can stick around and have minor impact on
+ # other performance sensitive workloads, so make sure we clean up.
+ self.target.execute("am force-stop {}".format(self.chrome_package))
+
+ if self.cleanup_assets:
+ if self.ui_dump_loc is not None and self.target_file_was_created(
+ self.ui_dump_loc
+ ):
+ # The only thing left on device was the UI dump created by uiautomator.
+ self.target.execute("rm {}".format(self.ui_dump_loc), as_root=True)
+
+ # Clear the cache we used to check if the local storage directory exists.
+ self.target_file_was_seen.clear()
+ self.ui_dump_loc = None
+
+ @once
+ def finalize(self, context):
+ super(Speedometer, self).finalize(context)
+
+ # Shutdown the locally hosted version of Speedometer
+ self.archive_server.stop(self.target)
+
+
+class ArchiveServerThread(threading.Thread):
+ """Thread for running the HTTPServer"""
+
+ def __init__(self, httpd):
+ self._httpd = httpd
+ threading.Thread.__init__(self)
+
+ def run(self):
+ self._httpd.serve_forever()
+
+
+class DifferentDirectoryHTTPRequestHandler(SimpleHTTPRequestHandler):
+ """A version of SimpleHTTPRequestHandler that allows us to serve
+ relative files from a different directory than the current one.
+ This directory is captured in |document_root|. It also suppresses
+ logging."""
+
+ def translate_path(self, path):
+ document_root = self.server.document_root
+ path = SimpleHTTPRequestHandler.translate_path(self, path)
+ requested_uri = os.path.relpath(path, os.getcwd())
+ return os.path.join(document_root, requested_uri)
+
+ # Disable the logging.
+ # pylint: disable=redefined-builtin
+ def log_message(self, format, *args):
+ pass
+
+
+class ArchiveServer(object):
+ def __init__(self):
+ self._port = None
+
+ def start(self, document_root, target):
+ # Create the server, and find out the port we've been assigned...
+ self._httpd = HTTPServer(("", 0), DifferentDirectoryHTTPRequestHandler)
+ # (This property is expected to be read by the
+ # DifferentDirectoryHTTPRequestHandler.translate_path method.)
+ self._httpd.document_root = document_root
+ _, self._port = self._httpd.server_address
+
+ self._thread = ArchiveServerThread(self._httpd)
+ self._thread.start()
+
+ adb_command(target.adb_name, "reverse tcp:{0} tcp:{0}".format(self._port))
+
+ def stop(self, target):
+ adb_command(target.adb_name, "reverse --remove tcp:{}".format(self._port))
+
+ self._httpd.shutdown()
+ self._thread.join()
+
+ def get_port(self):
+ return self._port
diff --git a/wa/workloads/speedometer/com.arm.wa.uiauto.speedometer.apk b/wa/workloads/speedometer/com.arm.wa.uiauto.speedometer.apk
deleted file mode 100755
index 08272095..00000000
Binary files a/wa/workloads/speedometer/com.arm.wa.uiauto.speedometer.apk and /dev/null differ
diff --git a/wa/workloads/speedometer/speedometer_archive.tgz b/wa/workloads/speedometer/speedometer_archive.tgz
new file mode 100644
index 00000000..cea62d3f
Binary files /dev/null and b/wa/workloads/speedometer/speedometer_archive.tgz differ
diff --git a/wa/workloads/speedometer/uiauto/app/build.gradle b/wa/workloads/speedometer/uiauto/app/build.gradle
deleted file mode 100644
index a0b38647..00000000
--- a/wa/workloads/speedometer/uiauto/app/build.gradle
+++ /dev/null
@@ -1,41 +0,0 @@
-apply plugin: 'com.android.application'
-
-def packageName = "com.arm.wa.uiauto.speedometer"
-
-android {
- compileSdkVersion 28
- buildToolsVersion "28.0.3"
- defaultConfig {
- applicationId "${packageName}"
- minSdkVersion 18
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- applicationVariants.all { variant ->
- variant.outputs.each { output ->
- output.outputFile = file("$project.buildDir/apk/${packageName}.apk")
- }
- }
- }
-}
-
-dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support.test:runner:0.5'
- compile 'com.android.support.test:rules:0.5'
- compile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
- compile(name: 'uiauto', ext:'aar')
-}
-
-repositories {
- flatDir {
- dirs 'libs'
- }
-}
diff --git a/wa/workloads/speedometer/uiauto/app/src/main/AndroidManifest.xml b/wa/workloads/speedometer/uiauto/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 46dfd769..00000000
--- a/wa/workloads/speedometer/uiauto/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/wa/workloads/speedometer/uiauto/app/src/main/java/com/arm/wa/uiauto/speedometer/UiAutomation.java b/wa/workloads/speedometer/uiauto/app/src/main/java/com/arm/wa/uiauto/speedometer/UiAutomation.java
deleted file mode 100755
index 13456635..00000000
--- a/wa/workloads/speedometer/uiauto/app/src/main/java/com/arm/wa/uiauto/speedometer/UiAutomation.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/* Copyright 2014-2018 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.arm.wa.uiauto.speedometer;
-
-import android.os.Bundle;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
-
-import com.arm.wa.uiauto.BaseUiAutomation;
-import android.util.Log;
-
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeUnit;
-
-@RunWith(AndroidJUnit4.class)
-public class UiAutomation extends BaseUiAutomation {
-
- private int networkTimeoutSecs = 30;
- private long networkTimeout = TimeUnit.SECONDS.toMillis(networkTimeoutSecs);
- public static String TAG = "UXPERF";
- public boolean textenabled = false;
- private String speedometerVersion;
-
- @Before
- public void initialize(){
- Bundle params = getParams();
- speedometerVersion = params.getString("version");
- initialize_instrumentation();
- }
-
- @Test
- public void setup() throws Exception{
- setScreenOrientation(ScreenOrientation.NATURAL);
- dismissChromePopup();
- openSpeedometer();
- }
-
- @Test
- public void runWorkload() throws Exception {
- runBenchmark();
- }
-
- @Test
- public void teardown() throws Exception{
- clearTabs();
- unsetScreenOrientation();
- }
-
- public void runBenchmark() throws Exception {
- UiObject start =
- mDevice.findObject(new UiSelector().description("Start Test")
- .className("android.widget.Button"));
-
- UiObject starttext =
- mDevice.findObject(new UiSelector().text("Start Test")
- .className("android.widget.Button"));
-
- // Run speedometer test
- if (start.waitForExists(10000)) {
- start.click();
- } else {
- starttext.click();
- }
- UiObject scores =
- mDevice.findObject(new UiSelector().resourceId("result-number")
- .className("android.view.View"));
- scores.waitForExists(2100000);
- getScores(scores);
- }
-
- public void openSpeedometer() throws Exception {
- UiObject urlBar =
- mDevice.findObject(new UiSelector().resourceId("com.android.chrome:id/url_bar"));
-
- UiObject searchBox = mDevice.findObject(new UiSelector().resourceId("com.android.chrome:id/search_box_text"));
-
- if (!urlBar.waitForExists(5000)) {
- searchBox.click();
- }
-
- String url = "http://browserbench.org/Speedometer" + speedometerVersion;
- if (speedometerVersion.equals("1.0")) {
- url = "http://browserbench.org/Speedometer";
- }
- // Clicking search box turns it into url bar on some deivces
- if(urlBar.waitForExists(2000)) {
- urlBar.click();
- sleep(2);
- urlBar.setText(url);
- } else {
- searchBox.setText(url);
- }
- pressEnter();
- }
-
- public void getScores(UiObject scores) throws Exception {
- boolean isScoreAvailable = false;
- int waitAttempts = 0;
- while (!isScoreAvailable && waitAttempts < 10) {
- sleep(1);
- if (!scores.getText().isEmpty() || !scores.getContentDescription().isEmpty()) {
- isScoreAvailable = true;
- }
- waitAttempts++;
- }
-
- String textScore = scores.getText();
- String descScore = scores.getContentDescription();
- // Chrome throws loads of errors on some devices clogging up logcat so clear tabs before saving score.
- clearTabs();
- Log.i(TAG, "Speedometer Score " + textScore);
- Log.i(TAG, "Speedometer Score " + descScore);
- }
-
- public void clearTabs() throws Exception {
- UiObject tabselector =
- mDevice.findObject(new UiSelector().resourceId("com.android.chrome:id/tab_switcher_button")
- .className("android.widget.ImageButton"));
- if (!tabselector.exists()){
- return;
- }
- tabselector.click();
- UiObject menu =
- mDevice.findObject(new UiSelector().resourceId("com.android.chrome:id/menu_button")
- .className("android.widget.ImageButton"));
- menu.click();
- UiObject closetabs =
- mDevice.findObject(new UiSelector().textContains("Close all tabs"));
- if (closetabs.exists()){
- closetabs.click();
- }
- }
-}
diff --git a/wa/workloads/speedometer/uiauto/build.gradle b/wa/workloads/speedometer/uiauto/build.gradle
deleted file mode 100644
index d0aa7043..00000000
--- a/wa/workloads/speedometer/uiauto/build.gradle
+++ /dev/null
@@ -1,23 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:2.3.2'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- jcenter()
- }
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/wa/workloads/speedometer/uiauto/build.sh b/wa/workloads/speedometer/uiauto/build.sh
deleted file mode 100755
index 237c0b92..00000000
--- a/wa/workloads/speedometer/uiauto/build.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash
-# Copyright 2018 ARM Limited
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-
-# CD into build dir if possible - allows building from any directory
-script_path='.'
-if `readlink -f $0 &>/dev/null`; then
- script_path=`readlink -f $0 2>/dev/null`
-fi
-script_dir=`dirname $script_path`
-cd $script_dir
-
-# Ensure gradelw exists before starting
-if [[ ! -f gradlew ]]; then
- echo 'gradlew file not found! Check that you are in the right directory.'
- exit 9
-fi
-
-# Copy base class library from wa dist
-libs_dir=app/libs
-base_class=`python3 -c "import os, wa; print(os.path.join(os.path.dirname(wa.__file__), 'framework', 'uiauto', 'uiauto.aar'))"`
-mkdir -p $libs_dir
-cp $base_class $libs_dir
-
-# Build and return appropriate exit code if failed
-# gradle build
-./gradlew clean :app:assembleDebug
-exit_code=$?
-if [[ $exit_code -ne 0 ]]; then
- echo "ERROR: 'gradle build' exited with code $exit_code"
- exit $exit_code
-fi
-
-# If successful move APK file to workload folder (overwrite previous)
-package=com.arm.wa.uiauto.speedometer
-rm -f ../$package
-if [[ -f app/build/apk/$package.apk ]]; then
- cp app/build/apk/$package.apk ../$package.apk
-else
- echo 'ERROR: UiAutomator apk could not be found!'
- exit 9
-fi
diff --git a/wa/workloads/speedometer/uiauto/gradle/wrapper/gradle-wrapper.jar b/wa/workloads/speedometer/uiauto/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 13372aef..00000000
Binary files a/wa/workloads/speedometer/uiauto/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/wa/workloads/speedometer/uiauto/gradle/wrapper/gradle-wrapper.properties b/wa/workloads/speedometer/uiauto/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 760fcce7..00000000
--- a/wa/workloads/speedometer/uiauto/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Wed May 03 15:42:44 BST 2017
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/wa/workloads/speedometer/uiauto/gradlew b/wa/workloads/speedometer/uiauto/gradlew
deleted file mode 100755
index 9d82f789..00000000
--- a/wa/workloads/speedometer/uiauto/gradlew
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env bash
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
- echo "$*"
-}
-
-die ( ) {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
-esac
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/wa/workloads/speedometer/uiauto/gradlew.bat b/wa/workloads/speedometer/uiauto/gradlew.bat
deleted file mode 100644
index aec99730..00000000
--- a/wa/workloads/speedometer/uiauto/gradlew.bat
+++ /dev/null
@@ -1,90 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/wa/workloads/speedometer/uiauto/settings.gradle b/wa/workloads/speedometer/uiauto/settings.gradle
deleted file mode 100644
index e7b4def4..00000000
--- a/wa/workloads/speedometer/uiauto/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include ':app'