1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-07-15 19:43:28 +01:00

701 Commits

Author SHA1 Message Date
e1e5d466a2 version: Version Bump to 2.7.0 2018-07-06 14:44:08 +01:00
3a863fa143 doc/requirements: Force sphinx to be an older version.
Readthedocs has updated their default sphinx version to be
incompatible with how our api is generated so force read the docs to use
the latest known working version (1.6.5)
2018-05-29 11:49:39 +01:00
e548e75017 Add a banner to readme pointing everyone to "next" 2018-05-25 17:27:08 +01:00
1b0799bcc5 wlauto/utils/ssh.py: Fix set terminal window size
Ensure that the terminal window size is set to 500x200, if not long
commands (prompt + command > 80 chars) will fail because the pexpect
search to match the command string in order to get the result and the
command is wrapped to first 80 chars.

For example, when check a file and executes:

...
if [ -f '/sys/kernel/debug/sched_features' ]; then echo 1; else echo 0; fi
...
File
\"/usr/local/lib/python2.7/dist-packages/wlauto/common/linux/device.py\",
line 228, in get_properties
if self.is_file(propfile):
File
\"/usr/local/lib/python2.7/dist-packages/wlauto/common/linux/device.py\",
line 215, in is_file
return boolean(output.split()[-1])  # pylint: disable=maybe-no-member

IndexError(list index out of range)
...

In order to fix this scenario enables checkwinsize in the shell and use
stty to set the new terminal window size.

Signed-off-by: Aníbal Limón <anibal.limon@linaro.org>
2018-04-16 14:16:06 +01:00
ea22bc062e recentfling: Add the ability to specify the device_name
Not all devices are supported by recentfling, but there is usually a
device that is supported and has a similar screensize.  Let the
recentfling workload specify the device to let us run it on more
devices.
2018-03-29 11:29:32 +01:00
ba6889ea7f android/workload: Move parameter from GameWorkload to ApkWorkload Class
In addition to `GameWorkloads` some benchmarks also download additional
data upon initialisation. Moving this parameter to the `ApkWorkload`
parent class allows all APK based workloads to indicate that their data
should not be cleared prior to running the workload.
2018-02-08 15:02:42 +00:00
9a9e8395cf instrumentation/fps: Fix spaces in SurfaceFlinger.
When parsing the SurfaceFlinger list output spaces were used as
separators. Some view names have spaces enclosed.
This would lead to views with spaces in their names not being correctly
detected and as a consequence the fps stats not collected.
2018-02-02 13:52:48 +00:00
0995e57689 instrumentation/fps: Allow measuring of views containing spaces
Ensure the view name is passed in quotes to allow for views containing
spaces.
2018-02-01 12:28:00 +00:00
7c920f953c resource_getters: Add support for matching apks via package name
Allows distinguishing between apks based on the package name specified
in the workload.
2018-01-23 13:08:39 +00:00
e5417e5b7f resource_getters: Change ExtensionAssetGetter to look in local env
Previously `ExtensionAssetGetter` subclassed `DependencyFileGetter`,
 commit 6e7087ee88 changed its
functionality to use a cached location instead of the local resource
location. This commit changes the `ExtensionAssetGetter` to subclass
`EnvironmentDependencyGetter` so it checks the local resource location
again.
2018-01-17 18:32:22 +00:00
d295b7d92d external/revent: make inlines static
Add "static" qualifier to inline functions. This avoids linking errors
when compiling without -O flags. The "static" forces the inlining as
described here:

https://gcc.gnu.org/onlinedocs/gcc/Inline.html
2017-12-04 11:17:24 +00:00
e33245ac72 external/revent: replace bzero with memset
Replace calls to bzero with equivalent calls to memset, as bzero is
deprecated and may not be supported by all tool chains.
2017-11-30 17:52:54 +00:00
57a8e62be9 util/android, get_apk_versions: try to find 'aapt' in $PATH as well
Some Linux distro provide android build-tools in packages, we should also try
to find 'aapt' in $PATH if it cannot be found in $ANDROID_HOME.
2017-11-28 09:14:50 +00:00
7ce1044eff trace-cmd: Update armeabi binary to LSB version.
The armeabi version of trac-cmd binary was erroniously built as
MSB which pervented it from being used.
2017-11-06 16:24:57 +00:00
5a70ab8534 Merge pull request from jimboatarm/androbench_update
Androbench: Updating Versions
2017-10-11 15:36:08 +01:00
486c0c6887 Androbench: Updating Versions
Updating the workload to work with version 5.0 of the Androbench application.
2017-10-11 15:22:22 +01:00
9e498a911e Merge pull request from setrofim/master
applaunch: do not attempt to uninstall uiauto apk
2017-09-21 17:15:35 +01:00
3d80e4ef34 applaunch: do not attempt to uninstall uiauto apk
applaunch  users the UI automation of the guest workload to detect
launch completion. However, the guest's automaiton apk is pushed to the
target and loaded via DexLoader; it is never actually installed;
therefore, it should not be uninstalled when running guest's teardown.
2017-09-21 16:53:13 +01:00
713fcc44d9 Merge pull request from setrofim/master
gmail: add missing import
2017-09-21 15:26:28 +01:00
39bc8eae20 gmail: add missing import 2017-09-21 15:25:58 +01:00
adf13feb81 Merge pull request from setrofim/master
utils/ipython: handle nbconvert import
2017-09-14 08:37:52 +01:00
b312bf317d utils/ipython: handle nbconvert import
nbconvert has been split into a separate package and is installed as a
dependency for Jupyter rather than IPython. Add a proper import guard
to prevent issues for those that don't need ipython_converter
functionality, and set the appropriate error message for those that do.
2017-09-14 08:35:41 +01:00
d8a5d2fa37 Merge pull request from setrofim/master
utils/ssh: fix telnet connection
2017-09-13 11:25:03 +01:00
a3d042e054 utils/ssh: fix telnet connection
This fixes the ability to connect over telnet rather than SSH which was
broken by commit 51db53d9

	 ssh: Back-port ssh_get_shell from devlib
2017-09-13 11:22:29 +01:00
afe3c16908 Merge pull request from bjackman/config-example-update
config_example: Update comment on available devices
2017-09-05 15:33:56 +01:00
5eee03c689 Merge pull request from bjackman/ipynb-exporter-tweaks
Ipynb exporter tweaks
2017-09-05 15:33:25 +01:00
6266edad6f ipython: Add support for IPython 5
This does not seem to require any change beyond incrementing the
recognised version number.
2017-09-05 14:55:59 +01:00
64426601fe ipynb_exporter: Use file_path to allow '~' in path parameters 2017-09-05 14:55:58 +01:00
cea39a6193 utils/types: Add file_path type
This can be used to allow extension parameters that are paths to use
'~' to refer to the home directory.
2017-09-05 14:55:56 +01:00
c952b2f0d4 config_example: Update comment on available devices 2017-09-05 12:23:37 +01:00
ea05022f5f Merge pull request from setrofim/master
spec2000: fix cpumask for genric
2017-08-22 15:40:22 +01:00
cdc7c96cdf spec2000: fix cpumask for generic
spec2000 expects binaries to be optimised for particular cores and uses
Device's core_names to figure out which cores the benchmark should run
on.

There is one special case, which is "generic", which is not optimised
for a particular uarch. cpumask for this was resolved the same way,
failing the lookup, resulting in the invalid mask 0x0.

To fix this, "generic" is now handled by specifying the mask for all
available CPUs.
2017-08-22 15:38:27 +01:00
2f683e59d2 Merge pull request from marcbonnici/FPS_Fix
Fps fix
2017-08-17 11:00:02 +01:00
6915de98f1 Merge pull request from marcbonnici/documentation
README: Update documentation link to ReadTheDocs
2017-08-16 17:09:57 +01:00
27fd2a81d3 README: Update documentation link to ReadTheDocs 2017-08-16 16:41:57 +01:00
a1c19b55b8 Merge pull request from marcbonnici/documentation
Documentation Update
2017-08-16 16:35:07 +01:00
890f4309d4 Documentation: Adds a requirement.txt
In order to build the test documentation the python package `nose` is
required therefore this commit adds a requirements.txt to ensure the
package is available when building the documentation on RTD.
2017-08-16 16:24:38 +01:00
c8cb153f8e Documentation: Fixes missing links to Invocation label 2017-08-16 16:24:38 +01:00
10c1f64216 Documentation/build_instrumentation: Cleanup 2017-08-16 16:24:38 +01:00
f194ef281b Documentation/Builds: Delete previously generated docs
As the Makefile is no longer responsible for calling the extension and
instrumentation documentation ensure any previously generated
documentation is deleted from the respective build file.
2017-08-16 16:24:38 +01:00
4d607b46c5 Documentation/Makefile: Removed additional calls to doc generation
The documentation build process is now automatically called during the
sphinx build therefore the addtional calls from the Makefile have been
removed.
2017-08-16 16:24:38 +01:00
cdd0834447 Documentation: Modified conf.py to allow building on ReadTheDocs
This commit now automatically calls the extension and
instrumentation documention generator and calls Sphinx-api tool
to allow documention generation on ReadTheDocs.
2017-08-16 16:24:38 +01:00
4c0d3f8d20 Bootstrap: Fixes not using newly created config files
If the $WA_USER_DIRECTORY folder is not present on the users
system it is automatically created and a default config.py file
created. Previously this newly created file would not be loaded into
WA causing it to crash.
2017-08-16 16:24:38 +01:00
8dcf1ba6a5 Bootstrap: Make sure that _env_root is an absolute path
If the environment variable $WA_USER_DIRECTORY is not set `_env_root`
is automatically generated from the path expansion of `~`. In some cases
if a home directory is not avaliable for the user this may result in an empty
string. This commit ensure that '_env_root' is still an absolute path
using the current working directory.
2017-08-16 16:24:13 +01:00
081358769d Workload/Manual: Update "view" parameter description 2017-08-15 10:34:37 +01:00
10a614ff04 Workload/Manual: Adds package parameter to workload
Adds the `package` parameter to allow the workload to be used
with the gfxinfo method of collecting data for the FPS instrument.
2017-08-15 10:34:37 +01:00
58a8ea9051 Instrumentation/FPS: Fixes attribute checking
Previously only the requirements for using SurfaceFlinger were checked,
regardless of the FPS method being used.
This commit now only ensure that a `View` attribute is present when
using SurfaceFlinge and a `package` name is available if using gfxinfo
otherwise falling back to SurfaceFlinger.
2017-08-15 10:22:59 +01:00
335fff2a6f Merge pull request from sdpenguin/master
revent.py: Fix handling of zero-event files
2017-08-11 17:43:06 +01:00
cd0863d7fa revent.py: Fix handling of zero-event files
Previously the try clause worked to catch StopIteration exceptions correctly,
however upon catching the exception, another statment which set self._duration
to (last.time - first.time) was being run regardless, which defeated the point
of the try clause.

This has been fixed by introducing an else clause to contain said statement.
2017-08-11 16:58:44 +01:00
5cd9bc756c Merge pull request from setrofim/master
revent: fix playback timing
2017-08-10 09:44:00 +01:00
362e93c4cb revent: fix playback timing
This fixes an issue introduced by commit 5965956

	revent: fix off-by-one in replay

This moved the updating of the current event to the beginning of the
body of the loop, after the check of the while loop to prevent attempting
to assign past the end of array. The problem is that one the conditions
in the check relies on the event being updated, so it need to happen
before that part of the loop condition check.

This move event update back to the end of the loop body, but it moves
the array bounds check from the while loop condition into the body, just
before the update but after the counter is incremented. This should
satisfy both, the counter being bounds checked before it is used, and
the event being updated to the next one to be played before the timing
check in the loop condition.
2017-08-09 17:50:54 +01:00
3f7d44de28 Merge pull request from sdpenguin/revent_integrated
ReventWorkload becomes an Linux (not Android) workload + fixes.
2017-08-09 14:22:35 +01:00
f35c444ddb generic_linux: Remove forbidden chars from device_model
Fix for Chromebook Plus and possibly other devices - removes forbidden
characters from the device_model such as the null character which was
causing a problem with getters getting file names including device_model.
2017-08-09 14:18:38 +01:00
e35d0f2959 wa record: Update -h description for ReventWorkload
Added information pertaining to the new .teardown file and several
rewordings.
2017-08-09 14:18:38 +01:00
6d9a03ad8f ReventWorkload: Move class to linux and add features
The ReventWorkload class has been moved to the linux directory and
two new features have been added: the option to run an idle workload
and the option to specify a .teardown revent file as well as a .setup file
which runs in the eponymous stage.
2017-08-09 14:18:38 +01:00
c6cdd8c0e6 Merge pull request from Sticklyman1936/patch-1
gem5: fixed a typo
2017-08-08 16:48:58 +01:00
8cf4c259c0 gem5: fixed a typo
Changed "self.longdelay" to "self.long_delay".
2017-08-08 16:34:52 +01:00
77bb14331f Merge pull request from marcbonnici/param_dict_fix
Types: Fix parameter dict get method
2017-08-08 08:28:04 +01:00
dd8843d24a Merge pull request from marcbonnici/documentation
Documentation fixes
2017-08-04 16:20:35 +01:00
16b302679a workloads/appshare: Fixes missing new line in doc string 2017-08-04 16:12:22 +01:00
f9db0a3798 workloads/rt-app: Fixes typos 2017-08-04 16:12:20 +01:00
548eb99bdc workloads/rt-app: Removed absoulte path in documentation
Removed dynamically populated existing configs path from doc string as
this is also used to generate the online documentation and therefore should
not be an absolute path.
2017-08-04 16:11:53 +01:00
f4669e2b20 Merge pull request from jimboatarm/scojac01-updated-workloads
AdobeReader: Updated to handle latest version
2017-08-04 13:08:29 +01:00
0578f26bc7 AdobeReader: Updated to handle latest version
The workload has been updated to handle the latest version
which no longer has the welcome view page. This has been
done so in a way that still provides backwards compatibility
to previous versions.
2017-08-04 10:16:14 +01:00
12230da959 Merge pull request from jimboatarm/scojac01-updated-workloads
Reworking the Gmail and GooglePlayBooks workloads to work with the la…
2017-08-03 10:00:19 +01:00
afa2e307cc Gmail: Updated to work with Android 7
Android 7 no longer has the broadcast functions which
mean we have to refresh our image directory another way.
We are now using Google Photos to do this but only if the
current method is unable to find the correct test images.
2017-08-03 09:56:47 +01:00
d662498ea8 GooglePlayBooks: Updated workload to work with the latest version
GooglePlayBooks UI has changed significantly in the latest
version. This includes extra dialog boxes upon first use
which need to be handled.
2017-08-03 09:56:47 +01:00
9e934c6733 Merge pull request from setrofim/master
revent: fix off-by-one in replay
2017-08-02 17:57:32 +01:00
596595698d revent: fix off-by-one in replay
Update idx and ev to the next event after the while check (which makes
sure that the next index is within bounds) to avoid a potential
access-past-end-of-array.
2017-08-02 17:52:04 +01:00
220e0962e1 Merge pull request from setrofim/master
Device: raise RuntimeError in _check_ready
2017-08-02 13:43:06 +01:00
be3c91b131 Device: raise RuntimeError in _check_ready
Previously, a AttributeError has been raised. This causes issues when
attempting to access some properties that rely on invoking commands on
the device. The error would get swallowed up in Python attribute
resolution machinery, resulting in an error claiming a missing
attribute.

For example, for AndroidDevice, "abi" is a property that internally
calls getprop(), which executes on the device, and thus requires a
connection. If attempting to access device.abi before device.connect()
has been invoked, the following sequence takes place

1. Caller tries to access attribute "abi" of device, which resolves to
   the device.abi property defined in the class.
2. device.abi calls device.getprop()
3. ...which calls device.execute()
4. ...which calls device._check_ready()
5. device._check_ready() raises AttributeError('device not ready.')
6. That gets propagated all the way up to 1., which gets interpreted
   as attribute not being found.
7. Since AndroidDevice defines a __getattr__(), that gets called next
8. __getattr__() looks for a loaded Device module that has an "abi"
   attribute. Since there isn't one, it raises AttributeError('abi').

The result is that the error reports a missing "abi" attribute, rather
than "device not ready", leading to some fun debugging.

Raising RuntimeError (which more appropriate for the circumstances
anyway) does not trigger __getattr__, so the correct error message is
reported to the user. The text of the message has also been adjusted to
make it clearer what has likely gone wrong.
2017-08-02 13:39:55 +01:00
efad084b24 Merge pull request from setrofim/master
utils/trace_cmd: expect ': ' in task name
2017-07-24 16:40:09 +01:00
6da0550b98 utils/trace_cmd: expect ': ' in task name
': ' is used as the delimiter for the different parts of of the event
line; unfortunately, it is also a valid character sequence to appear in
a task name.

This change attempts to perform the event line split correctly by
ensuring that the cpu id is present in the first part.
2017-07-24 09:31:31 +01:00
9500bcd914 Merge pull request from setrofim/master
utils/trace_cmd: fix event parsing
2017-07-20 17:10:21 +01:00
7f8e7fed4b utils/trace_cmd: fix event parsing
Make event preamble parsing more robust in cases there are multiple
instances of ' [' (e.g. as part of thread name) by splitting exactly
once from the right. The right-most columns are the timestamp and the
cpu id, and much more restricted (and therefore predictable) in their
formatting.
2017-07-20 15:52:31 +01:00
87972e2605 Merge pull request from setrofim/trace-cmd-optimization
Optimize parsing of trace-cmd output
2017-07-20 11:48:03 +01:00
33874a8f71 utils/trace_cmd: reduce regex use
Do not attempt to regex match each line for dropped events/preamble. Use
substring search to detect them first, and only use regex on relevant
lines.
2017-07-20 11:12:54 +01:00
93dba8b35d utils/trace_cmd: optimize event parsing
Use string searching and splitting instead of regex matching to parse
trace events. This significantly speeds up trace parsing.
2017-07-20 11:12:53 +01:00
6f629601be utils/trace_cmd: lazy evaluation of event fields
Parsing if a trace events body text into fields is potentially
expensive, so only do it if the fields are being accessed.
2017-07-20 11:12:53 +01:00
565f352114 Merge pull request from setrofim/master
AndroidDevice: adjust APK install timeout to 5min
2017-07-19 10:02:18 +01:00
920d80ad6e AndroidDevice: adjust APK install timeout to 5min
install_apk() was using the default timeout of 30 seconds, this can
cause problems for some applications on slower targets. Since
installation is expected to be a long-ish operation, there is not reason
for the timeout to be this short.

This commit adjusts the timeout to 5 minutes, which should be a more
reasonable value for most applications. For some apps with particularly
large APKs, this may not be enough, but in those cases, the default
should already be overriden on per-worload bases.
2017-07-19 10:01:00 +01:00
9962b413d7 Merge pull request from yln/master
Update docs
2017-07-13 08:08:13 +01:00
fdff80a72b Merge pull request from marcbonnici/fire_adobereader
Misc Fixes
2017-07-13 08:06:30 +01:00
6cc4626f50 Update docs: $WA_HOME -> $WA_USER_DIRECTORY 2017-07-12 16:02:02 -07:00
665d76456b Merge pull request from setrofim/master
utils/android: better error massage when no exit code found
2017-07-12 13:36:09 +01:00
f4b91b6c9e utils/android: better error massage when no exit code found
Provide the stdout/stderr text as part of the messsage in the
exception raised when no exit code can be identified from the adb
command output.
2017-07-12 13:34:20 +01:00
4730ac2989 AndroidWorkload: Removal of explicit parameter setting
'exact_abi' was being explicitly set without proper checking, however
this should already be taken care of in the supers automagic parameter
setting.
2017-07-12 09:48:03 +01:00
6737fda24e AdobeReader: Removes use of device search button
On amazon fire tablets the search button triggers a custom implemented
search dialog instead of performing a search within the app.
2017-07-12 09:48:03 +01:00
f72bf95612 Types: Fix parameter dict get method
The overridden get method was incorrectly using __getitem__() when decoding the
data instead of get().
2017-07-10 11:30:54 +01:00
2a07ed92fe Merge pull request from marcbonnici/sysfs_fix
Instrumentation: Fixes SysfsExtractor with tmpfs
2017-07-10 08:24:00 +01:00
a4c7340746 Instrumentation: Fixes SysfsExtractor with tmpfs
Previously due to WA automagic the initialization method would only be
called once globally, meaning that it was called for cpufreq extraction
but not for sysfiles. This commit splits SysfsExtractor into a base
FsExtractor and a SysfsExtractor subclass and the initialization methods
are explicitly called by both children.
2017-07-07 17:43:43 +01:00
6eb4e59129 Merge pull request from bjackman/geekbench-corporate
geekbench: Fix running multiple 'times' on Geekbench 4
2017-07-06 11:29:27 +01:00
d65561e3e9 geekbench: Fix running multiple 'times' on Geekbench 4
You only have to press the back button once to get back to the "run
benchmarks" screen.
2017-07-06 11:12:19 +01:00
64d3ddc8e6 Merge pull request from bjackman/geekbench-corporate
Geekbench: Add support for Corporate version
2017-07-05 11:45:32 +01:00
579b940d75 Merge pull request from setrofim/master
trace-cmd: documentation fixes.
2017-07-05 08:39:54 +01:00
0656e61bc2 Geekbench: Add support for Corporate version
The Corporate version is a specialised version of Geekbench. It has
different package names and does not require dismissing a EULA. The
new corporate version is added as a distinct
benchmark ("geekbench-corporate" vs "geekbench").

Note that this changes the wait-for-results UiAutomator snippet from
looking for "Running Benchmarks..." to "*Running*". This is because
the version I've tested updates the text widget with the name of each
benchmark phase as it is run. However I don't know if this is a
feature of the Corporate version or simply of Geekbench 4.1.0.
2017-07-04 18:05:20 +01:00
13e787b5d0 trace-cmd: documentation fixes.
- Remove reference to default events from the overall workload
  documentation. It was, as of recently, outdated, and was also
  redundant, as the actual defaults will be in the parameter-specific
  documentation.
- Remove reference to Android-specific trace-cmd binary -- this was not
  true for a long time.
- Clarify that the on-host trace-cmd binary is now optional due to the
  report_on_target config.
- Fix a few misc typos.
2017-07-04 16:53:32 +01:00
4d7ef408c9 Merge pull request from bjackman/remove-cpufreq-interactive
trace-cmd: remove cpufreq_interactive from default events
2017-07-04 13:23:33 +01:00
a533680e49 trace-cmd: remove cpufreq_interactive from default events
The interactive governor isn't standard any more (and was
Android-only anyway). Remove this default so you don't get errors for
kernels that don't support it.
2017-07-04 12:15:18 +01:00
4ddb6f44fc geekbench: correct v3 version number
Current APK discovery rules will match against full APK version string,
so must be "3.0.0" rather than just "3".
2017-07-03 17:50:44 +01:00
1238cb71f0 ssh: raise correct error on EOF
Raise DeviceError, rather than TargetError, on EOF inside ssh_get_shell.
This is a fix for an issue introduced by a devlib backport in 51db53d9.
2017-07-03 11:01:11 +01:00
53203bfb50 Merge pull request from setrofim/master
AndroidDevice: more robust getprop parsing
2017-06-28 17:23:56 +01:00
11859af894 AndroidDevice: more robust getprop parsing
Ran into a development target on which one of the values in getprop
output contained a new line. Updating getprop parsing logic to handle
such cases by switching to a regex.
2017-06-28 17:05:47 +01:00
1f5f9cf478 Merge pull request from setrofim/master
acmecape: echo command that is going to be used
2017-06-28 11:52:57 +01:00
52a07160b9 acmecape: echo command that is going to be used 2017-06-28 11:49:20 +01:00
0d8204121d Merge pull request from setrofim/master
ApkWorkload: only uninstall if package is already installed
2017-06-22 14:43:45 +01:00
a47d6c6521 ApkWorkload: only uninstall if package is already installed
Attempting to uninstall an non-existing package will result in an error.
So, when replace=True for install_apk(), only attempt to uninstall if
the package is already present on the target.
2017-06-22 14:31:25 +01:00
d391b28d2e Merge pull request from AnthonyARM/master
Fixed missing comma in list
2017-06-21 16:43:35 +01:00
e42099851b Fixed missing comma in list 2017-06-21 16:41:12 +01:00
0c0ccb10d9 Merge pull request from setrofim/master
cpustates: workaround for disabled cpuidle
2017-06-21 15:31:47 +01:00
486494f1f2 cpustates: workaround for disabled cpuidle
Add "no_idle" parameter to work around the problem where cores are
reported to be in "unknown" state if there are no cpuidle transitions in
the trace. If this parameter is set, cpustates will assume cores are
active without waiting for an idle transition.
2017-06-21 15:30:43 +01:00
919a44baec Merge pull request from setrofim/master
Revert "cpustates: fix idle state assumption on freq transition"
2017-06-21 14:22:58 +01:00
4f09c3118a Revert "cpustates: fix idle state assumption on freq transition"
This reverts commit 9bd745b347.

When a frequency is changed on a core, cpufreq reports a frequency
transition for all cores in the frequency domain. This means it is not
safe to assume a core is not idling just because there is a frequency
transition reported for it (that just means that there is at least one
core on that frequency domain that is not idling). Moreover, the
transitions are always reported in the same order so there is no way to
infer which core triggered it.
2017-06-21 14:13:24 +01:00
b6b1b259dc Merge pull request from setrofim/acmecape
instrumetnation: add support for BayLibre ACME cape
2017-06-21 09:30:47 +01:00
f1b63b239c Merge pull request from setrofim/master
cpustates: fix idle state assumption on freq transition
2017-06-20 16:03:36 +01:00
797cb3c9ea Merge pull request from marcbonnici/uiauto_install
AndroidWorkload: Uninstall uiauto apks before reinstalling
2017-06-20 15:58:42 +01:00
9bd745b347 cpustates: fix idle state assumption on freq transition
If a frequency transition is observed before an idle state can be
established, assume idle state is -1 (i.e. the core is running). This
will ensure correct stats for platforms with disabled cpuidle.
2017-06-20 15:48:51 +01:00
9f3ecd3715 AndroidWorkload: Uninstall uiauto apks before reinstalling
Due to the fact that uiauto apk files built on different machines will
be signed with different keys, adb will fail to overwrite a previous
version even when set to replace. This commit now will uninstall the
previous uiauto apk file if present before attempting to install the new
version.
2017-06-20 15:19:19 +01:00
1a177dd52f Merge pull request from jimboatarm/skype-timeoutincrease
Skype: Change timeout value for endcall
2017-06-20 15:05:21 +01:00
4010618631 Skype: Change timeout value for endcall
New override function added which uses uiAutoTimeout if no timeout value
has been specified.
Checking against the endcall button now uses this method.

Tested on a Huawei Mate 8 Device with just core 0 enabled (slowing it
down enough that the previous timeout of 0.5s caused the workload to
fail)
2017-06-20 15:01:05 +01:00
1168c1ada8 Merge pull request from marcbonnici/googleslides
GoogleSlides and Books Fixes
2017-06-20 10:35:09 +01:00
8b7db92ab8 Googleslides: Fixes images not being found on some chromebooks.
On some chromebooks the "images" tab does not appear when attempting to
insert an image, instead the desired image needs to be found via local
storage.
2017-06-20 10:04:13 +01:00
088102a81d GooglePlayBooks: Fixes
Updated to add in workarounds for cases where the workload would fail to
find elements correctly.
2017-06-19 16:33:49 +01:00
87ce1fd0ae instrumentation: add support for BayLibre ACME cape
Add an instrument for collecting power and energy from BayLibre
ACME cape probe.
2017-06-16 11:32:14 +01:00
4fac39ada9 GoogleSlides: Fixed bug where settings could not be opened
For some reason although the settings element could be found, clicking
on it did not have the desired effect, to solve this the element has
been found as a UiObject2 instead.
2017-06-15 17:22:57 +01:00
81fa5fdf81 Merge pull request from bjackman/gfxinfo-ignore-extra-fields
fps: Ignore additional fields in gfxinfo frame data
2017-06-15 15:47:03 +01:00
2702731532 fps: Ignore additional fields in gfxinfo frame data
Some versions of Android include additional fields in gfinxo which we
don't care about. The existing fields have the same order, so simply
ignore the extra ones.
2017-06-15 15:20:12 +01:00
b95ea60213 Merge pull request from marcbonnici/uiauto_timeout
Workload: Increased default uiautomator workload timeout
2017-06-15 11:27:32 +01:00
8acebe12bd Workload: Increased default uiautomator workload timeout
After the upgrade to uiauto2 some workloads seem to take slightly longer
than previously.
2017-06-15 11:23:38 +01:00
2172db5833 Merge pull request from AnthonyARM/master
Replaced active_cpus by online_cpus in common/linux/device.py
2017-06-15 09:58:47 +01:00
ff67ed1697 Replaced active_cpus by online_cpus in common/linux/device.py 2017-06-14 14:25:17 +01:00
ae1a5019dc Merge pull request from setrofim/master
ssh: Back-port ssh_get_shell from devlib
2017-06-14 13:13:23 +01:00
51db53d979 ssh: Back-port ssh_get_shell from devlib
This back-ports ssh_get_shell implementation from devlib. It includes
the following changes:

- original_prompt for Telnet verison of the connection can now be passed
  as an argument.
- Multiple attempts to connect with a timeout.
- Some additional implementation to the tty, including setting the size.
2017-06-13 09:14:26 +01:00
42a4831092 Merge pull request from marcbonnici/online_cores
Online cores
2017-06-13 08:55:47 +01:00
8e94b79ed8 LinuxDevice: Now raises an error if trying to hotplug all cores.
Previously this would try to automatically enable an additional core to ensure
that all cores were not hot-plugged, however it would do this unnecessarily if
another core that wasn't the first of its types was already online.
2017-06-12 17:56:06 +01:00
37d99e4a5d LinuxDevice: Remove duplicate method and rename for consistency
These function were duplicated of each other so one has been removed and the
remaining methods renamed for consistency with WA terminology and the relevant
calls updated.
2017-06-12 17:27:21 +01:00
0683427acd Merge pull request from marcbonnici/signal_fix
EntryPoint: Fixes local package being used over system level
2017-06-09 12:59:28 +01:00
64574b1d4c EntryPoint: Fixes local package being used over system level
Due to a local file named 'signal.py' this was being imported instead of the system level 'signal' package. This commit ensures the the system level is used instead.
2017-06-09 11:10:44 +01:00
3653e1b507 Merge pull request from marcbonnici/uiauto2
Uiauto2 - Fixes
2017-06-08 17:52:38 +01:00
e62262dbb3 Uiauto2 Workloads: Fixes applaunch bug in androind N
In order to workaround an bug in applaunch running on android N, all of the
workloads have been updated to the latest gradle build system, the timeout in
the baseclass has been changed from a TimeUnit to a regualr long and a
duplicately declared parameter bundle has been removed.
2017-06-08 16:55:47 +01:00
18e47c89c5 Skype: Fixes launch command for intrumented testing.
Without specifying user `-3' for the launch command, the application is by default
attempted to be launched with permissions that are only grantable to system
apps.
2017-06-08 16:55:41 +01:00
389a1ecf76 Merge pull request from AnthonyARM/master
Convert TERM signals into INT to allow WA to exit cleanly
2017-06-08 15:16:48 +01:00
260e9563b3 Convert TERM signals into INT to allow WA to exit cleanly 2017-06-08 14:09:15 +01:00
48d0e1196c Merge pull request from marcbonnici/uiauto2
Uiauto2: Fixes leftover references to `.uiautoapk`
2017-06-08 11:41:51 +01:00
b64c615e8e Uiauto2: Fixes leftover references to .uiautoapk 2017-06-08 11:23:45 +01:00
a4e27128e5 Merge pull request from marcbonnici/uiauto2
Uiautomator2: Fix for newer adb versions.
2017-06-08 10:57:49 +01:00
242cf7e33a Revert "Android Device: Add force flag to install_apk"
This reverts commit 5d8305cfdc.
2017-06-05 17:00:40 +01:00
cc641e8dac UiautoWorkloads: Updated to use apk files for uiautoamtion tests. 2017-06-05 17:00:40 +01:00
bb17590689 ResourceGetter: Updated to check if an apk is a uiautomation test apk.
The getter now checks the apk package name to distinguish between a regular
android apk and a uiautomator apk.
2017-06-05 17:00:40 +01:00
4ce38fcd55 Revert "ResourceGetters: Added support for finding uiautoapk files."
This reverts commit b948d28c62.
2017-06-05 16:55:47 +01:00
bf694ffdf1 Revert "AndroidResource: Add a UiautoApk resource type."
This reverts commit bc6af25366.
2017-06-05 16:55:47 +01:00
b36e0061e1 AndroidWorkload: Updated to use an 'APK' file instead of a 'uiautoapk' 2017-06-05 16:55:47 +01:00
526ad15c01 AndroidResource: Updated APKFile to add support for uiautomator tests.
In newer versions of adb, files cannot be installed unless they use the
`.apk` extension therefore we need to be able to distinguish between
regular apks and instrumented test files.
2017-06-05 16:55:38 +01:00
0694ab6792 LinuxDevice: rename get_number_of_online_cpus arg
Renamed "c" to "core", as that gets passed as a keyword argument inside
get_runtime_parameters().
2017-06-01 14:29:19 +01:00
2fd7614d97 Merge pull request from marcbonnici/uiauto2
Upgrading to UiAutomator2
2017-05-31 11:22:45 +01:00
c75c102cd2 Merge pull request from setrofim/master
utils/trace_cmd: add parsers for more sched events
2017-05-31 10:48:14 +01:00
c86ce64408 utils/trace_cmd: add parsers for more sched events
Added parsers for sched_wakeup(_new) and sched_stat_* events that have
non-standard text.
2017-05-31 10:42:55 +01:00
d6909c5e6a PowerUtils: Pylint Fix 2017-05-31 10:36:38 +01:00
55e140f20a Caffeinemark: Updated to Uiautomator2 2017-05-31 10:36:38 +01:00
0c7a7e4dca BenchmarkPi: Updated to uiautomator2 2017-05-31 10:36:38 +01:00
a7ed00d9ed Googleslides: Add workaround for opening navigation drawer
On Android N running under the instrumentation uiautomator appears to have
trouble retrieving the root node for the home screen of google slides. Therefore
we open the navigation drawer via a swipe which allows the node to be found again.
2017-05-31 10:36:38 +01:00
89aa3e1208 GoogleSlides: Updated to uiautomator2
The latest version of uiautomator2 seems to have an issue with google slides not
being able to interact with any elements on the slide therefore we are using a
slightly older version which doesn't have this issue.
2017-05-31 10:36:38 +01:00
f33fd97705 Videostreaming: Updated to uiautomator2 2017-05-31 10:36:38 +01:00
bf598d1873 Camerarecord: Updated to only use root if device is rooted.
Previously the workload would always try and use root to pull framestats file
causing it to fail on unrooted devices.
2017-05-31 10:36:38 +01:00
c094a47f12 Camerarecord: Updated to uiautomator2 2017-05-31 10:36:38 +01:00
6dab2b48ab Cameracapture: Updated to uiautomator2 2017-05-31 10:36:38 +01:00
1809def83f Peacekeeper: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
1158c62c55 Appshare: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
d13defe242 Glbenchmark: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
a9c5ab9bc8 Facebook: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
27af97b795 Quadrant: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
a0a189044e Applaunch: Updated to Uiautomator2
Certain configurations of this workload requires root and therefore on some
android devices, this will prompt to grant the app su permissions by default. To
ensure this does not interfere with the run, ensure that either, re-request
permission after reinstall/upgrade is not selected or grant access by default.
2017-05-31 10:36:37 +01:00
eca6c10a75 Andebench: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
01efbe1807 Googlephotos: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
81f7f92b84 real_linpack: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
95c98fd458 Antutu: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
428abfb6a6 Geekbench: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
a8bf8458ec Youtube: Updated to Uiautomator2 2017-05-31 10:36:37 +01:00
862eeadb39 Vellamo: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
ec66e1d166 Sqlitebm: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
3e4ffa8cd5 Smartbench: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
dc14e6ed11 Linpack: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
47ccae1a6b Googleplaybooks: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
a2eef179ef Gmail: Updated to work on new app version. 2017-05-31 10:36:36 +01:00
7eb36b959b Gmail: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
b5563113b1 Cfbench: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
5720d3f214 Androbench: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
5b82b90939 Skype: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
bfcb829ab0 AdobeReader: Updated to Uiautomator2 2017-05-31 10:36:36 +01:00
70f646f87d AndroidWorkload: Added unchangeable android permissions
Some android permissions are categorized as 'unchangeable' so we don't need to
try and set them.
2017-05-31 10:36:35 +01:00
3f03dec7af CreateCommand: Updated to support new build system
Using the `android` command to create a new project has been deprecated in favour
of using Android Studio. To avoid this constraint a template project has been added
and this is simply duplicated with the relevant files populated when creating a new
project.
2017-05-31 10:36:35 +01:00
076772da4d Uiautomator: Upgraded uiautomator base classes to Uiauto2
Uiautomator1 has been deprecated, therefore the uiautomation base classes have
been upgraded to use uiautomator2 and the new gradle build system.
Altered to retrieve `package_name` rather than `package` as per the previous commit.
2017-05-30 17:26:14 +01:00
138c95745e AndroidWorkload: Renamed package parameter to package_name
Using the new instrumental based testing method, `package` is a reserved
parameter and is not passed to the workload correctly.
2017-05-30 12:06:50 +01:00
f517e6c4da .gitignore: Updated for new uiauto2 gradle based builds 2017-05-30 12:06:50 +01:00
8125c3e0a2 Android Workload: Updated to install and use Uiautomator 2 tests.
The new method of using uiautomation 2 is by using instrumented apk files rather
than JAR files. This commit updates the base workload has been updated to
install/uninstall the new uiautomation APK files and to invoke the relevant
instrumentation.
2017-05-30 12:06:50 +01:00
81bdc7251b AndroidDevice: Pylint Fix 2017-05-30 12:06:36 +01:00
b948d28c62 ResourceGetters: Added support for finding uiautoapk files.
Also ensures to check for a `.` to signify the start of a file extension to prevent
extensions with the same ending being mixed up.
2017-05-23 11:16:18 +01:00
bc6af25366 AndroidResource: Add a UiautoApk resource type.
When moving to Uiautomation 2, tests are now complied into apk files rather than
jar files. To avoid conflicts with regular workload apks a new resource type is
added to retrieve the test files which will be renamed to have the extension
.uiautoapk
2017-05-23 11:15:55 +01:00
5d8305cfdc Android Device: Add force flag to install_apk
A force flag has been added to the `install_apk` method which
ignores the check that the specified file is an apk. This is to support
the new UiAutomation Apk which have been given the extention .uiautoapk.
2017-05-17 13:47:39 +01:00
e038fb924a Merge pull request from marcbonnici/broadcast
Update media broadcast to work with android N
2017-05-12 08:01:04 +01:00
51c92cb2f5 Workloads: Updated to use new media refresh method
Updated the base android workload and google photos workload to pass a list of
updated files rather than their directory.
2017-05-11 18:17:38 +01:00
e98b653b3e AndroidDevice: Add refresh_device_files method
Adds a method to determine the appropriate method of triggering a media refresh
of a given list of file based on the devices android version and root status. If
a device is running android marshmallow and below or has root, trigger a refresh
of the files containing folder otherwise trigger a refresh of each individual
file.
2017-05-11 18:17:38 +01:00
b1da0fe958 AndroidDevice: Add a common_base_path utility function
Adds a utility function to determine the lowest common base path of a passed list
of files.
2017-05-11 18:17:29 +01:00
b10b5970c3 AndroidDevice: Add a broadcast_media_scan_file method
In android N it is no longer allowed to trigger a media refresh of a directory
without root, therefore this method has been added to trigger a refresh of an
individual file.
2017-05-11 09:44:49 +01:00
e866cfed12 AndroidDevice: Add as_root flag to broadcast_media_mounted
Allows the `MEDIA_MOUNTED` broadcast to be performed as root as
this now requires elevated permission in android N.
2017-05-11 09:11:24 +01:00
f5b40e3d64 AndroidUtils: Updated Android_Version_Map
Added Marshmallow and Nougat SDK versions codes to the version map.
2017-05-11 09:11:23 +01:00
cc3a815cb7 uxperf workloads: only broadcast media mounted if needed
Previously AndroidPerfWorkload broadcast media mounted unconditionally
inside push_assets and delete_assets. This change makes it so the
broadcast only happens if something was actually pushed/needs to be
delete.
2017-05-10 15:42:10 +01:00
9ef8bddc4b Merge pull request from jimboatarm/gbfix
Fix geekbench to use new ParameterDict types
2017-04-26 08:15:06 +01:00
a3011accf8 Fix geekbench to use new ParameterDict types
Tested using Huawei P10
2017-04-25 18:12:48 +01:00
317da0a1c4 trace-cmd: updating trace-cmd binary to a more recent version
The one we currently have is over two years old. This is, in particular,
for the following fixes:

https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git/commit/?id=e5e453917f247faa7d37728d59001759e7005258
https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git/commit/?id=709b47c3f7d4e41e89ee58a85cd106456f779445
2017-04-20 16:25:57 +01:00
7c79c24865 rt-app: fix classifer update
rt-app inserts its own classifiers into the results. Previosly, if was
replacing the existing classifier if there were any. Now, classifiers
are updated, rather than replaced.
2017-04-07 16:33:24 +01:00
6c5e52ad56 freqsweep: fixing additional classifiers
Properly handle the case where additional classifiers are not specified.
2017-04-07 10:05:29 +01:00
1019b30174 Merge pull request from marcbonnici/binary_sysfile
Device: Updated to set and retrieve binary data from sysfiles
2017-04-06 16:11:13 +01:00
50236b0661 Device: Updated to set and retrieve binary data from sysfiles
`set_sysfile_values` now accepts a `^` symbol prefixed to the
file path to indicated that the value should be written as binary data.
To accommodate this an extra `binary` flag has been added to  the `set_sysfile_value`and `get_sysfile_value` methods to write and retrieve the binary data respectively.
2017-04-06 15:59:01 +01:00
6cfcb89827 Merge pull request from setrofim/master
freqsweep: added support for additional classifiers
2017-04-06 15:01:07 +01:00
cf0a4d3ff3 freqsweep: added support for additional classifiers 2017-04-05 14:48:11 +01:00
06764dff00 Merge pull request from setrofim/master
cpustates state tracking fix and a new output option
2017-03-29 10:02:48 +01:00
8f2ff4d2f8 cpustates: fix cluster shutdown tracking
This commit resolves a couple of issues that were causing impropper
cluster shutdown tracking in the cpustates script.

- requested_states in the PowerStateProcessor was being initalized to -1
  instead of None if no state was requested; the later checks are
  against None.
- requested_states was not being set if the request could be satisfied
  immediately, and was being cleared upon being statisfied at a later
  time. This caused a problem when a core leaves idle and then tries to
  re-enter cluster shutdown. Here is an example sequence of events that
  illustrates the issue (assume core0 and core1 are the only two cores
  on a cluster):

  	1. both cores are running
	2. core0 requests cluster-sleep. As core1 is running, it
	   is put into core-sleep instead, and its request is saved.
	3. core1 requests cluster-sleep. As core0 has a pending request
	   for cluster-sleep, both cores are put into cluster-sleep and
	   the pending request is cleared.
	4. core1 becomes active. core0 is elevated to core-sleep.
	5. core1 tries to enter cluster-sleep. Since core0 is currently
	   in core-sleep (and its prior request has laredy been
	   cleared), core1 is put into core-sleep instead, and its
	   request is saved. This is an ERROR as but cores have in fact
	   requested cluster-sleep at this stage.

  If, in step 4., core0 becomes active instead, exactly the same
  situation will result, as core1 was put into cluster-sleep immediately
  and its request was never saved.
  Idle state requests are now always tracked on entry and are only
  cleared when the core leave idle.
- Also removed a pointless identy assignment.
2017-03-24 08:55:47 +00:00
9a9de99c5f cpustates: added transition timeline option
Added an option to generate a timeline of state transitions, in
contrast to the existing timeline of computed states. This is primarily
intended for debugging of the latter, but may also be useful for certain
kinds of analyses.
2017-03-23 14:01:14 +00:00
f52aa0f7e9 Merge pull request from jimboatarm/appsharefix
Appshare .jar rebuild
2017-03-22 12:25:36 +00:00
935edcdd01 Appshare .jar rebuild
Rebuilding the .jar file as it is not up to date with the current source.
2017-03-22 12:23:35 +00:00
869c0bc6bd meizumx6: fix: changing is_rooted to be a property 2017-03-16 13:40:39 +00:00
57ab97df89 Merge pull request from jimboatarm/googleplaybooks_intfix
Googleplaybooks: Updating workload to work with change in parameter types
2017-03-09 17:11:18 +00:00
773bf26ff2 Googleplaybooks: Updating workload to work with change in parameter t…
…ypes

Due to a change in the parameter kind we have to update the googleplaybooks workload to work with integers for page numbers as opposed to strings.

This was missed in the previous update: 8f12066
2017-03-09 16:50:26 +00:00
2822949517 Merge pull request from marcbonnici/facebook_fix
Facebook: Updated workload to work with server changes.
2017-03-06 08:13:10 +00:00
4dc0aaa724 Facebook: Updated workload to work with server changes.
Fixed being unable to find the 'update status' box.
Now selects a 'do you know' notification rather than the latest,
as this is now a link on how to upgrade the app which opens in
external browser.
2017-03-03 16:38:23 +00:00
35df2fff30 Merge pull request from Sticklyman1936/device_sleep
Extend device with sleep functionality
2017-03-02 15:02:04 +00:00
4abbe7602a Extend device with sleep functionality
This changeset adds the ability to sleep on the device via a
device.sleep() method. This invokes sleep on the target device. This
is useful for situations where the passage of time on the target
device does not match that of the host, e.g., gem5.

This changeset also updates a number of workloads to use this new
sleep method.
2017-03-02 14:22:05 +00:00
55e40ded1c Merge pull request from Sticklyman1936/audio_fix
Remove stale browser-specific commands from audio workload
2017-03-02 10:46:18 +00:00
441ecfa98c Remove stale browser-specific commands from audio workload
In this changeset we remove some left over browser specific commands
which are no longer required as part of the audio workload.
2017-03-02 10:40:11 +00:00
7130b3a4ab Removing browser launch from audio and video
For historical reasons audio and video workloads were launching the
browser as part of their setup. This is no longer necessary. Not only
that, since on recent devices the default Android browser is missing,
this causes problems with the workloads. This commit removes the browser
launch.
2017-03-02 10:29:00 +00:00
510abf4666 Merge pull request from jimboatarm/fps-override
Allow user to override the method of collecting FPS data
2017-02-24 16:33:31 +00:00
70b265dd34 fps: Added parameter to override FPS collection method
In Android M and above, there is a new method of collecting fps
statistics, using gfxinfo rather than SurfaceFlinger, but the
SF method is still available however.
This parameter lets the user decide whether to always use SF,
or to allow the instrument to pick the best method based on
Android version it detects.
2017-02-24 16:22:16 +00:00
ddbd94b2a8 Merge pull request from jimboatarm/nanologger
Changed ActionLogger class to use nano timestamps.
2017-02-24 16:20:04 +00:00
c4025cad66 Changed ActionLogger class to use nano timestamps. This is because fps instrument collects data in ns as well so is possible to match the two 2017-02-24 16:11:35 +00:00
38b368eec2 Merge pull request from marcbonnici/uiautomator
UXPerfUiAutomation and AppShare Workload Updated
2017-02-23 08:44:11 +00:00
2e97bcce70 Appshare: Fixed typo 2017-02-22 16:25:59 +00:00
9b13f65895 AppShare: Added check to see if additional back press is required.
On some devices after signing into skype, the back button press only
hides the keyboard and a second is required to return to the previous
app.
2017-02-22 16:25:55 +00:00
78c1a80a51 Appshare: Updated to work with new sharing selector name.
On nexus 10 the app share selector has a new name, this commit
checks for either and uses the appropriate one.
2017-02-22 16:22:55 +00:00
7f85da6633 AppShare: Updated to use new method of uiautomator parameter passing. 2017-02-22 16:22:55 +00:00
f76d9f9a1f Appshare: Updated to use new methods in UxPerf.
The appshare workload has been updated to use the new getter/setter
methods added to UXPerf rather than accessing protect variables.
2017-02-22 16:21:37 +00:00
6ffed382cf UxPerfUiAutomation: Added setWorkloadParameters and getPackageID.
To work around appshare requiring access to protected variables of a workload,
a `setWorkloadParameters` method has been added to manually supply a parameter
bundle, and a `getPackageID` method to retrieve a workloads package ID.
2017-02-22 16:21:10 +00:00
6e7087ee88 resource: remote resource resolution fixes
- "remote" getter priority reduced to be below "environment" so that
  resouces placed into "~/.workload_automation/dependencies" by the user
  take priority over those pulled from remote locations.
- "filer" getter now uses a cache location for the resource rather than
  downloading to the local resource location.
2017-02-21 16:35:16 +00:00
96c6f010f8 Merge pull request from marcbonnici/uiautomator
UIAutomator
2017-02-20 17:47:03 +00:00
8f1206678a UiAutomatorWorkloads: Updated to use the new parameter passing functionality.
Each workload has be modfied to remove the old manual paremeter conversion
and instead to retrieve the desired type from the parameter bundle directly.
2017-02-20 16:44:24 +00:00
d10e51e30b UiAutomator: Updated to decode provided parameters from ParameterDict
To prevent parameters having to be converted individually for each worload
the getParams() function has been overridden to perform the required type and
url decoding on the passed parameter bundle before passing the correctly typed
bundle to the workloads.
2017-02-20 16:44:24 +00:00
bd0a6ac3c8 UiAutomatorWorkload: Changed to use a ParameterDict
Due to the limitations of UiAutomator, parameters are not allowed to contain
certain characters including spaces and newlines when passed on the command line.

The python UiAutomatorWorkload baseclasse has been updated to use a
ParameterDict when storing workload parameters.
2017-02-20 16:44:24 +00:00
9ba30c27df WA Types: Added 'ParameterDict' type.
A new 'ParameterDict' has been added that automatically encodes and
decodes values when they are store in a dictionary. The dictionary uses 2 characters
prefixed to each value to store the original type information, e.g. 'fl' -> list of
floats, before being passed through a url encoder. The reverse process happens on retrieval.
To access the encoded values an `iterEncodedItems` and `getEncodedValue` methods have been added.

The appropriate unit tests have also been added.
2017-02-20 16:44:24 +00:00
8f40e6aa40 PEP8 / Pylint Fixes 2017-02-20 16:44:24 +00:00
8c9ae6db53 AndroidWorkload: Split up setup_workload_apk method.
Split up `setup_workload_apk` method into smaller methods to improve readability.
2017-02-20 16:44:24 +00:00
6ac0c20619 Merge pull request from jimboatarm/scojac01-appshareupdate
Removed surplus back command that was causing AppShare workload to fail
2017-02-20 15:03:20 +00:00
cfa1827445 Removing surplus spaces that were added with previous commit 2017-02-20 14:43:01 +00:00
821cbaff4e Removed surplus back command that was causing AppShare workload to fail 2017-02-20 12:00:49 +00:00
c7db9a4543 Merge pull request from jimboatarm/scojac01-slidesupdate
Updated googleslides workload to work with latest supported APK
2017-02-17 15:33:57 +00:00
6f67f00834 Added functions to work with the latest supported APK, to handle the pop up message looking to prompt the user to update and to handle the issue where the save/insert new slide button is not seen when running in maximum window on certain devices. 2017-02-17 15:16:41 +00:00
40db6a9933 meizumx64: always unrooted
This implements a workaround for the Meizu MX6. "su" in the rooted
version is broken from WA's perspective so all devices should be
considered unrooted.
2017-02-16 13:25:58 +00:00
543228f7c3 Merge pull request from marcbonnici/staleclasses
UiAutomator: Removed stale class files.
2017-02-10 08:15:07 +00:00
58b97305d5 Merge pull request from jimboatarm/skype-interface
Skype: implement ApplaunchInterface
2017-02-07 13:46:27 +00:00
0246302814 Merge pull request from jimboatarm/googleplaybooks-interface
Googleplaybooks: implement ApplaunchInterface
2017-02-07 13:44:15 +00:00
0aee99a79c Merge pull request from jimboatarm/youtube-interface
Youtube: implement ApplaunchInterface
2017-02-07 13:43:29 +00:00
5012ab5f1b Merge pull request from jimboatarm/googlephotos-interface
Googlephotos: implement ApplaunchInterface
2017-02-07 13:42:42 +00:00
b7b2406a25 Merge pull request from jimboatarm/fps_issue
Applaunch: Update package to measured workload pkg.
2017-02-07 13:32:09 +00:00
cd05c36250 Skype: implement ApplaunchInterface
Adapts skype workload to support applaunch workload by implementing
the required methods of the interface.

Tested on Huawei Mate8 and Samsung S7.
2017-02-07 10:45:29 +00:00
b169b45e57 Applaunch: Update package to measured workload pkg.
Application launch workload runs the package of the workload which is being
instrumented. Fps instrumentation requires the package name and hence the
package name is changed to the workload package name during initialization.

Tested on Huawei Mate8 with fps instrumentation ON.
2017-02-06 17:01:09 +00:00
40cc830de1 Merge pull request from marcbonnici/adobereaderfix
AdobeReader: Updated workload to work with latest version.
2017-02-06 08:10:27 +00:00
1ebe56ca76 Googlephotos: implement ApplaunchInterface
Adapt googlephotos to support applaunch workload by implementing the methods
required by the interface.

Tested on Huawei Mate8 and Samsung S7.
2017-02-05 12:28:37 +00:00
79f58e74b9 Googleplaybooks: implement ApplaunchInterface
Adapt googleplaybooks to support applaunch workload by implementing the methods
required by the interface.

Tested on Huawei Mate8 and Samsung S7.
2017-02-05 12:18:31 +00:00
7fe699eb41 Youtube: implement ApplaunchInterface
Adapt youtube to support applaunch workload by implementing the required methods of the interface.

Tested on Huwaei Mate8 and Samsung S7.
2017-02-05 11:52:20 +00:00
2bd77f0833 UiAutomator: Removed unnecessary class files.
Removed stale classes from the repository.
2017-02-03 17:14:33 +00:00
7b7eb05e7f AdobeReader: Updated workload to work with latest version.
The 'My Documents' element that the workload used to check for completed
setup has been removed in the latest version, now checks for the
text itself which is also present in previous versions.
2017-02-03 15:42:53 +00:00
ae0c9fa60b Merge pull request from jimboatarm/applaunch-interface-v2
Applaunch Workload
2017-02-03 15:25:16 +00:00
75b56e462c Adobereader: implement ApplaunchInterface
Adapts adobereader to support uxperfapplaunch workload by implementing the required methods
of the interface.

Tested on Huwaei Mate8 and Samsung S7.
2017-02-03 15:15:05 +00:00
d8438c5ae8 Gmail: implement ApplaunchInterface
Adapts gmail workload to support applaunch workload by implementing the
required methods of the interface.

Tested on Huawei Mate8 and Samsung S7.
2017-02-03 15:14:56 +00:00
ca7a1abe78 Add new applaunch workload.
The workload supports launch time measurement of other uxperf workloads that
implement the ApplicationlaunchInterface. It takes a uxperf workload as a parameter
and helps to instrument the application launch time in two modes.

a)launch_from_background
b)launch_from_long_idle

The workload executes in two major phases.
1- Setup phase: clears initial dialogues on the first launch of an application.
2- Run phase: Runs multiple iterations of the application launch and measures
the time taken for launch. Iteration number can be specified as parameter applaunch_iterations.

Applaunch measurements are captured in the logcat file.
2017-02-03 15:14:47 +00:00
bd37973442 Remove existing applaunch workload
The applaunch workload is deprecated to be replaced by another implementation.
2017-02-03 15:14:37 +00:00
c38dc287ab Move UxperfParser into utils
UxperfParser class is moved from the UxperfResultProcessor class into a new
python module in utils. This will help to use the UxperfParser even when
the result procesor is not configured.
2017-02-03 15:14:27 +00:00
3feb702898 fps: move VSYNC_INTERVAL into utils
It is not anything to do with instrument, but a generic ocnstant,
and this way it can be used by the other parts of the code line.
2017-02-03 15:14:16 +00:00
0f57dee6bf Add ApplaunchInterface class
Inorder to support application launch workload, a new interface is created
which has methods that need to be implemented by all workloads that
support application launch time instrumentation.
2017-02-03 15:14:03 +00:00
99b46b4630 Add UiAutoUtils class
UiAutoUtility class added to support utility functions used for UiAutomation.
This class can help in refactoring some existing fucntionalities into utility functions.

Launch command generation is added as a utility class method which can be used
by workloads to construct their launch command from parameters passed.
2017-02-03 15:13:50 +00:00
4ce20e2d3f Move package parameters to UxperfUiAutomation
All the uxperf workloads get some common package parameters.
These are moved to the parent class and a new method is introduced to fill
these parameter values. All the uxperf workloads can call this method to resolve
the package parameters.
2017-02-03 15:13:32 +00:00
65aa00483b Add pressHome() method in the Base class
This function Presses Home button on the Android User Interface.
2017-02-03 15:12:35 +00:00
da7a3276ed Merge pull request from marcbonnici/revent_fix
Revent fix / improvments
2017-02-01 18:10:32 +00:00
b89d9bbc4b StateDetection: Moved check for missing phase definition earlier.
Now checks to see if a phase is correctly defined before image matching
so that it is only performed if required.
2017-02-01 18:04:05 +00:00
54bffb45ab Revent: Fixed uninitialized variable. 2017-02-01 18:04:05 +00:00
e7a47f602d Revent: Removed check for 'wait_for_stdin'.
Revent is terminated from WA via a 'SIGINT', therefore this means
that in order for revent to receive the signal and deal with it
accordingly, revent always needs to be listening on STDIN regardless of
the 'wait_for_stdin' flag.
2017-02-01 18:03:28 +00:00
490dd404ae AndroidDevice: write "dumpsys window" output on host
On Android targets, WA collects device display information by running
"dumpsys window" during run initialisation. Previously, this was
redirectied into on-device file (under the working directory) and then
pulled from the target.

It looks like on Android-on-ChromeOS devices the redirect leads to an
"Unknown Error" and the resulting file is empty. To get around that,
this commit modfies the dumpsys command so that the output is collected
directly from the shell's stdout and then writen on the host.
2017-01-24 17:52:51 +00:00
60f52c2187 Merge pull request from jimboatarm/multiapp-workload
Multiapp Workload: Workload to test how responsive a device is when…
2017-01-16 16:41:35 +00:00
fbb9908298 Merge pull request from jimboatarm/break_setup
Splits ApkWorkload setup() into short methods.
2017-01-13 15:39:11 +00:00
01fa0a3571 Splits ApkWorkload setup() into short methods.
Apkworkload setup phase performs many functionalities in
a single method that is broken down into short methods.
The split short methods can be called individually when
relevant use cases arise.
2017-01-13 11:56:39 +00:00
be2b14a575 Merge pull request from jimboatarm/skype_fix
Create a function for launching skype application.
2017-01-13 05:28:00 +00:00
dab2bbb1c7 Merge pull request from jimboatarm/epochtime
Changes Action Logger to give epoch time
2017-01-13 05:26:28 +00:00
340ae72ca2 Merge pull request from siddhanathan/typo
Fix typo
2017-01-13 05:25:02 +00:00
e64dc8bc26 Fix typo
Instrumention -> Instrumentation
2017-01-12 12:13:05 -08:00
cb48ece77f daq: fixing energy metric calculation
The summary energy metric was being calculated incorrectly. Instead of
dividing power by the sampling rate, it was being multiplied by it and
divided by a million for some reason.
2017-01-12 11:29:44 +00:00
8f67b7f94b Create a function for launching skype application.
Skype has a unique launch command which is called in the setup
phase of the workload. The launch command is split into a stand alone
method which can be called as a separate method if required.

This can be used as common method if more applications in future
require their own customized launch command.
2017-01-12 11:27:42 +00:00
fa553ee430 Changes Action Logger to give epoch time
Log time changed to produce epoch time in milli seconds.
Nano to milli second conversion done in uxperf result
processor is removed.

Tested on Mate8 and time obtained is verified.
2017-01-12 10:30:07 +00:00
01c9c88e79 perf: do not force root on Android in stop()
perf instrument was forcing killall() to run as root on Android devices.
This constraint was preventing perf from being used on unrooted devices.
However, it appears that it is possible for killall() to succeed on at
least some devices as a regular user.

This commit removes the constraint. Since killall() will default to
running as root whenever possible, the instrument will still behave
correctly on rooted Android devices where root is required.
2017-01-11 13:44:55 +00:00
0c32e39ce0 Merge pull request from jimboatarm/minapkremoved
Removed min_apk_version from UXperf workloads
2017-01-09 15:13:04 +00:00
1364ec05e8 Version bump 2016-12-23 14:14:43 +00:00
d5c888cc90 Merge pull request from marcbonnici/documentation
Documentation and get-assets Update
2016-12-23 14:13:30 +00:00
d6ab68bffc Documentation: Updated change log for new version. 2016-12-23 10:39:51 +00:00
30e9b553ff get_assets: Updated Remote Assets URL
Updated URL to new location of WA assets as previous URL was no longer found.
2016-12-23 10:39:51 +00:00
6a3f441064 Documentation: Added command info to invocation page.
Added `create` and `get-assets` command information to invocation
page of documentation.

Corrected spelling.
2016-12-23 10:39:51 +00:00
13cbe2f059 Renamed `get-assests.py to get_assests.py`
``get-assests.py`` is not a valid python module name therefore it has been
renamed to ``get_assests.py``, the command however remains with the same name.
2016-12-23 10:39:51 +00:00
53b173c55f Documentation Update
Updated documentation to conform with pylint and sphinx.
2016-12-23 10:39:51 +00:00
f598c60514 Merge pull request from marcbonnici/spec2000
Spec2000
2016-12-23 10:38:43 +00:00
ceda8e74bf Merge pull request from marcbonnici/poller
Poller
2016-12-23 10:35:44 +00:00
173c71b867 FilePoller: Updated 32 bit binary.
Recompiled the 32 bit binary as previous version would fail
due to missing applet.
2016-12-22 17:38:20 +00:00
d88d35be26 FilePoller: Made files a mandatory parameter.
Changed the `files` parameter to be mandatory and added check to
ensure that at least one file is passed in configuration otherwise
the instrument crashes.
2016-12-22 17:34:50 +00:00
599452d41f Merge pull request from marcbonnici/perf
Perf: Recompiled 32bit binary as little endian.
2016-12-22 11:04:14 +00:00
33dae51536 Merge pull request from marcbonnici/big.Little
big.Little Sample Agenda: Fixed workload name and typo.
2016-12-21 17:10:33 +00:00
f8950dea33 Merge pull request from marcbonnici/googlephotos
GooglePhotos: Updated to work with the latest version (v2.6.0).
2016-12-21 17:09:20 +00:00
136d1fef0f GooglePhotos: Updated to work with the latest version (v2.6.0).
Dismisses backup confirmation in newer versions.
Updated for new way of editing photo colours and lack of confirmation.
2016-12-21 17:05:09 +00:00
5204383582 Merge pull request from marcbonnici/netstat
NetStat: Updated Regex to match logcat format in android 6.0
2016-12-21 16:53:55 +00:00
bfa1d8dd62 Merge pull request from marcbonnici/dex2oat
Dex2oat: Now uses root if available.
2016-12-21 16:53:12 +00:00
b75fdf85d0 big.Little Sample Agenda: Fixed workload name and typo.
One of the workloads was listed as sqlite which is an instrument,
corrected the workload name to sqlitebm.

Added missing word in description.
2016-12-21 12:08:51 +00:00
fcbb83f5ac Spec2000 Workload: Spelling Corrected 2016-12-20 16:34:07 +00:00
807003128e Spec2000 Workload: Updated to use busybox provided from WA.
Commands have been updated to use the busybox executable that
is installed via WA rather than relying on it already being in
PATH on the device as this would fail for devices that it was
not installed on.
2016-12-20 16:20:59 +00:00
3e4d068eff NetStat: Updated Regex to match logcat format in android 6.0
Android marshmallow uses a different default view for logcat
therefore prevented output from being extracted. The regex
expression has been updated to include matching the new format.
2016-12-20 09:56:26 +00:00
a3936afb4c Perf: Recompiled 32bit binary for little endian.
Compiled 32bit perf binary as little endian instead of big
endian to support more devices.
2016-12-16 18:13:43 +00:00
24000a21df Dex2oat: Now uses root if available.
Command fails to execute with permission error on some devices therefore
now attempts to use root if available.
2016-12-16 11:20:37 +00:00
e5c0ca85f0 Merge pull request from jimboatarm/fix-adobereader
Fix adobereader
2016-12-15 17:07:12 +00:00
51f07c4473 Multiapp Workload: Workload to test how responsive a device is when context switching between appplication tasks. It combines workflows from googlephotos, gmail and skype.
Added tagName to give unique logger name for multiple share attempts. Turn off markers_enabled for subclasses

Renamed multiapp to appshare. Description is now more accurate

Changed appshare to use class instances for each sub workload. This allows APKs to be setup correctly on the device

Photos changed function name
2016-12-15 16:19:19 +00:00
ffde7401ef Removed min_apk_version from UXperf workloads. The known working version is now part of the description instead. 2016-12-15 16:13:58 +00:00
b4026ae390 Fix inverted swipe up/down gestures
Tested on Chromebook and Mate 8
2016-12-15 15:28:23 +00:00
f76c00dd99 Fix adobereader on S7
Tested on S7
2016-12-15 15:04:07 +00:00
b1e375a676 Merge pull request from marcbonnici/skype
SkypeWorkload: Workload Fixes
2016-12-15 11:18:24 +00:00
1102ba1679 SkypeWorkload: Workload Fixes
Fixed contact not being found when mistakenly selecting search for
bots instead of contact.

Changed element used to determine when contact has been
selected from status indicator to search icon as with other other
contacts in view the element is never removed.

Now throws error if end call button is not found otherwise workload
could fail to start the call and incorrectly report overall success.
2016-12-15 10:30:34 +00:00
6d999301f3 Merge pull request from marcbonnici/glbenchmark
glbenchmark: Updated version numbers from X.X.X to X.X.
2016-12-14 16:42:52 +00:00
e4fdf0bdb9 glbenchmark: Updated version numbers from X.X.X to X.X.
Apks contain version number in format X.X therefore when trying to
match for versions using X.X.X the apk is never found.
2016-12-14 15:37:07 +00:00
d493b1e790 Merge pull request from marcbonnici/exact_abi
Modified how apks containing native code are matched to a target devices supported abi(s).
2016-12-14 10:32:56 +00:00
47e31765b4 Merge pull request from marcbonnici/facebook
Facebook
2016-12-14 08:13:54 +00:00
79faec120e Merge pull request from marcbonnici/playbooks
GooglePlayWorkloads: Updated for new version.
2016-12-14 08:13:12 +00:00
66dbe7a508 GooglePlayWorkloads: Updated for new version. 2016-12-13 16:33:50 +00:00
80a780dcfe FacebookWorkload: Fixed UI automation and speificed maximum vesrion.
Fixed the workload UI automation and specified the version of
facebook that the workload is designed to work with.
2016-12-12 18:12:34 +00:00
694d51ffb6 AndroidWorkload: Fixed validate version error messages.
Fixed typos in ``validate_version`` method which caused incorrect reporting
of maximum apk version.
2016-12-12 18:09:40 +00:00
1befe63e45 Merge pull request from marcbonnici/peacekeeper
PeacekeeperWorkload: Updated to work with new APK versions
2016-12-12 16:59:38 +00:00
27b08bade0 PeacekeeperWorkload: Updated to work with new APK versions
Updated peacekeeper UI automation to work with newer version of
chrome and firefox.
2016-12-12 16:49:54 +00:00
1477a89ee4 AndroidDevice: Renamed 'supported_eabis' property to 'supported_abis'
Renamed android device property from 'supported_eabis' to 'supported_abis' to be consistent with linux device.

Updated dex2oat workload to use new property name.
2016-12-09 15:23:58 +00:00
0dfbbae7b6 Renamed 'check_abi' parameter to 'exact_abi' 2016-12-09 14:11:16 +00:00
a8a8d21de6 AndroidWorkload: Modified workload to properly check for an apks abi
Previously when retrieving apks only it's name would be used to choose
an apk. Now the native code reported by the apk is used to determine
the correct version to run for the specific device. It tries to
match the primary abi of device with native code before falling back to
using a compatible apk.

When using the check_abi parameter it no longer relies on naming convention
and only allows apks with native code supporting a devices primary abi to be
used.

Updated the relevant documentation.
2016-12-09 14:11:16 +00:00
f467f6f991 AndroidDevice: Added method to retrive primary abi of installed package
Tries to retireve the primary abi of a currently installed package on
device.
2016-12-09 14:11:16 +00:00
4352e02806 APK Info: Added property to extract native code from an apk
Looks for any native code present in an apk and stores the
mapped abi(s) for use when selecting appropriate apks.
2016-12-09 14:11:16 +00:00
693d0544a3 ABI_MAP: Added armeabi-v7a as armeabi 2016-12-09 14:11:16 +00:00
eb239c65d0 LinuxDevice: Added supported eabi property.
Added property to linux device to return list of supported abis
to be consistent with android devices. Currently only returns a
list containing the primary abi.
2016-12-09 14:11:16 +00:00
f7e4232eaa Merge pull request from jimboatarm/skype-waitonsignin
skype: longer wait time for signin and search
2016-12-09 13:44:40 +00:00
8cbf189029 skype: longer wait time for signin and search 2016-12-09 13:45:35 +00:00
6e45e1a039 Merge pull request from marcbonnici/adobereader
AdobeReader: Updated workload for new app version
2016-12-09 08:14:06 +00:00
b6f770cfc5 AdobeReader: Updated workload for new app version
Updated the workload to work with the latest version (v16.4)
of Adobe Reader app.
2016-12-08 18:14:16 +00:00
c7de8cabd6 Merge pull request from jimboatarm/improve-geekbench-timeouts
geekbench: Improve UiAutomator timeouts for slower devices
2016-12-02 17:04:01 +00:00
fd7df36a5a Merge pull request from jimboatarm/skype-hangup
skype: now hangs up at the end. Better duration handling
2016-12-02 17:03:13 +00:00
607187ad5b Merge pull request from marcbonnici/revent_BC
Revent: Fixed backwards compatibility with v1
2016-12-02 17:02:06 +00:00
b4036c5f15 Merge pull request from jimboatarm/uxperf-fix
UXPERF: handle error when only one timestamp is logged
2016-12-02 16:58:33 +00:00
b6e077c06b Revent: Fixed backwards compatibility with v1.
Fixed new gamemode not being set for compatibility mode.
Fixed input buffer not being flushed causing replay to fail.
Fixed infinte loop if revent recording did not end correctly.
Updated revent binaries.
2016-12-02 16:58:09 +00:00
8e0b793f89 Merge pull request from jimboatarm/utilfps-fix
util-fps: handle divide by zero possibility
2016-12-02 16:56:59 +00:00
8b82451230 util-fps: handle divide by zero possibility 2016-12-02 16:34:32 +00:00
64c352fab6 UXPERF: handle error when only one timestamp is logged 2016-12-02 16:31:45 +00:00
68697a42a7 Merge pull request from jimboatarm/photos-reliability
GooglePhotos: Navigate up only when needed.
2016-12-02 14:37:40 +00:00
ae4ae3da5e skype: now hangs up at the end. Better duration handling 2016-12-02 11:30:30 +00:00
393abc267f GooglePhotos: Navigate up only when needed. Use baseclass' selectGalleryFolder 2016-12-02 11:28:38 +00:00
751970f991 Merge pull request from marcbonnici/master
Revent: Added updated revent binaries.
2016-12-02 10:31:03 +00:00
254e9fff38 Revent: Added updated revent binaries.
Added updated revent binaries for armabi and arm64 for the fixes
in commit 7a19046645
2016-12-02 09:55:19 +00:00
088709f290 geekbench: Improve UiAutomator timeouts for slow devices, fixes for rooted devices
Tested by running Mate 8 on the lowest cluster at the lowest available frequency

On rooted devices, skip attempting to pull log files from device.  This allows
the benchmark to run to completion without failure.

GB log files are stored in /data/data/com.primatelabs.geekbench/files and
not accessible without root.  On Chromebooks ( which have no adb root
rights) it is possible to copy from this folder manually after the test run.
2016-12-02 07:23:44 +00:00
850fcb24ab pylint/pep8 fixes 2016-12-01 15:01:45 +00:00
ace41d10a5 Merge pull request from jimboatarm/gmail-workload
Gmail: A workload to perform standard productivity tasks within Gmail
2016-12-01 14:46:12 +00:00
cb53fe9ec8 Gmail: A workload to perform standard productivity tasks within Gmail. The workload carries out various tasks, such as creating new emails, attaching images and sending them.
Moved broadcast to super. Mandatory and Default are XOR

Added a longer wait for sync to finish. Increases reliability on certain phones

Changed recipient to not mandatory and a default set

Wait for sync when launching gmail from the sharing feature

Fix: cornercase where image viewer already points to working directory. Refactored code due to duplication

Added new function to BaseUiAutomation class to find a folder in the gallery
2016-12-01 13:21:49 +00:00
4e161127e1 Merge pull request from setrofim/master
A couple of fixes for trace CPU power state post-processing and energy model scripts
2016-11-30 09:38:05 +00:00
bf43bf93bc Merge pull request from marcbonnici/revent_fixes
Revent: Fixes
2016-11-29 17:34:17 +00:00
7a19046645 Revent: Fixes
Changed termination signal to interrupt signal to prevent code exiting too early.
Added exit handler to ensure revent exits correctly as previously was
crashing and therefore not running final code.
Fixed error in writing input event where half of timestamp seconds was missing.
Fixed typo in documentation for revent file structure.
2016-11-29 17:29:33 +00:00
5db11462be utils/power: handle devlib frequency reporting
When collecting ftrace events, the instrument will insert frequencies
into the trace to make it possible reconstruct power states when there
were no frequency transitions during the measured period.

The format in which frequencies are inserted is different in devlib.
Since post-processing scripts may be run on traces collected by devlib
as well as WA, it needs to support both formats.
2016-11-29 10:23:32 +00:00
7bf0e3c344 energy_model: only set "ui" parameter for ChomeOS
Fixed a bug, where "ui" runtime parameter was being set regardless of
the underlying platforms for "freq" iterations, causing the to fail on
non-ChomeOS devices.
2016-11-29 10:23:32 +00:00
d16d8bf62d Merge pull request from marcbonnici/octaned
ResourceGetters: Updated executable discovery to use http_getter
2016-11-28 11:45:46 +00:00
c93cc81aac ResourceGetters: Updated executable discovery to use http_getter
Executables were not previously automatically downloaded from a
provided remote_assets_url. The http_getter is now called to attempt to
find and download executable files.
2016-11-28 11:38:29 +00:00
9491763aa7 Merge pull request from jimboatarm/git_fix
Fixes gitignore to untrack files from uiauto
2016-11-28 11:05:24 +00:00
a172c8f624 Merge pull request from jimboatarm/fix-octaned8-log-appending
Fix octaned8 results capture
2016-11-28 11:04:42 +00:00
33286ba982 Merge pull request from jimboatarm/fix-exact-apk-version
Fix exact_apk_version check
2016-11-28 11:03:23 +00:00
f69e4c5b18 Fix octaned8 results capture
Ensure the device log file is deleted between runs and that the host file is not kept as an
artefact.  Both can lead to errors appending data from the next iteration/run.
2016-11-24 14:54:19 +00:00
5b543d2edf Fix exact_apk_version check 2016-11-24 12:47:57 +00:00
17edb13eb9 Fixes gitignore to untrack files from uiauto
Gitignore was untracking a few files from wlauto/external/uiautomator whereas
the folder name is uiauto instead. Name changing done to fix the bug.
2016-11-15 11:45:50 +00:00
40d281b336 Merge pull request from jimboatarm/octaned8
Add Octane d8 workload
2016-11-11 17:32:53 +00:00
74ea78aa42 Merge pull request from jimboatarm/fps-fix
FPS percentiles: Ignore ValueError when NaN
2016-11-11 17:32:21 +00:00
8edce40301 FPS percentiles: Ignore ValueError when NaN
Fixed: if index isnt zero based, drop(0) will fail
2016-11-11 17:21:47 +00:00
642d757066 Add Octane d8 workload
A workload to run the binary (non-browser) version of Octane
2016-11-11 17:04:25 +00:00
969201968e Merge pull request from jimboatarm/min-apk-version-fix
Support for Geekbench 4
2016-11-11 11:23:07 +00:00
3f76920fa9 Merge pull request from jimboatarm/testbranchplz
Change min apk ver for reader
2016-11-11 10:30:20 +00:00
46b78d35be Geekbench 4 is similar in terms of operation but runs significantly different tests and hence
produces a different results output.

- Add UiAutomator and results parsing support for GB4
- Remove the version checking in init.py and rely instead on the ApkWorkload version
  checking.  The required version in the agenda is checked against that on the host or target

Tested with GB3.4.1 and GB4.0.0 on a Galaxy S7.  Older variants of the APK were not available.
2016-11-10 18:56:22 +00:00
ba34b973ac ApkWorkload: add check for an exact APK version
Checks for an APK version on the host or target which matches a specified value
2016-11-10 18:46:31 +00:00
6d173f2f3f Change min apk ver for reader 2016-11-10 15:48:50 +00:00
8b1d2c9fe9 Merge pull request from Leo-Yan/add_camera_user_case_1110
rt-app: add user case for camera
2016-11-10 08:54:45 +00:00
d3c59e2f74 rt-app: add user case for camera
Add camera-long.json and camera-short.json files to simulate camera
 recorder.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
2016-11-10 12:08:02 +08:00
fce04d2938 Merge pull request from jimboatarm/uxperf-newfps
uxperf result_processor: updated for changes in FPS instrument
2016-11-08 13:20:31 +00:00
27df426c0d Merge pull request from jimboatarm/books-codetidy
GooglePlayBooks: Code tidy to conform.
2016-11-08 13:19:27 +00:00
f8966bf324 GooglePlayBooks: Code tidy to conform. Additional parameter added for when the search name differs to the library name. Defaults changed due to Hamlet dissapearing from the store.
Added cornercase of accidentially triggering a card popup

New version includes a new dialogue and name for search. Added support for this

If device has more than one account associated, a new popup appears. Handle that with an optional parameter listing specific account to select, if ommitted the first account in the list is selected
2016-11-08 12:31:27 +00:00
e076d47a7b uxperf result_processor: updated for changes in FPS instrument 2016-11-08 12:20:47 +00:00
ea798aefb3 Merge pull request from jimboatarm/fps-fix
FPS - fix regex and handle empty frames
2016-11-08 08:29:46 +00:00
dcf13f8c2c FPS - fix regex and handle empty frames 2016-11-07 17:39:51 +00:00
f99c6f5656 Merge pull request from jimboatarm/min-apk-version-fix
Fix incorrect min_apk_version setting in adobereader and googleplaybooks
2016-11-07 15:53:31 +00:00
359d9d3e5f Fix incorrect min_apk_version setting in adobereader and googleplaybooks 2016-11-07 15:42:38 +00:00
d56f581a0a Merge pull request from jimboatarm/fps-gfxinfo
FPS. Added gfxinfo methods of obtaining fps stats.
2016-11-04 17:11:59 +00:00
f12cf6d557 statedetect: pylint and dependencies fixes
- Corrected the depency for opencv bindings. Even though the library is
  imported as "cv2", the package containing it is called
  "opencv-python".
- pylint: ignore no-member warnings; cv2 pulls it's memebers dynamically
  from the underlying libopencv, so pylint can't see them.
2016-11-04 17:05:39 +00:00
311c4e419f FPS. Added gfxinfo methods of obtaining fps stats. Auto detects and uses appropriate method via android version of device
Output 90th, 95th and 99th percentile metrics. This happens for both SurfaceFlinger and Gfxinfo methods.
2016-11-04 17:05:00 +00:00
2becd94381 Merge pull request from marcbonnici/revent_statedetection
ReventWorkload: Modified statedection to vary scale of images
2016-11-04 15:39:23 +00:00
1daa7f97c0 ReventWorkload: Modified statedection to vary scale of images
Due to inaccuracies in revent playback, the resultant state does not
always match the templates precisely causing state detection to fail.
To help this images are now scaled to different sizes before being
matched to the templates to compensate for slight variations in size.
2016-11-04 15:25:31 +00:00
7af5868c22 Merge pull request from marcbonnici/android_utils
android: Fixed issue using single quoted command with adb_shell
2016-11-02 15:34:55 +00:00
2e1ce49170 android: Fixed issue using single quoted command with adb_shell
When using 'check_exit_code' and 'as_root' options for adb_shell with
a command containing single quotes, the provided command was escaped
twice which has now been avoided.
2016-11-02 14:52:47 +00:00
23eb357e9e Merge pull request from setrofim/master
revent: gamepad support and refactoring
2016-10-26 17:09:56 +01:00
71c5d23d97 revent: updated documentation to reflect recent changes
- Updated documentation for revent format to reflect the new
  format.
- Moved format documentation below state verification section, to the
  bottom of the document,as generally this will be the least-sought
  section.
- Updated usage to document -g option
2016-10-26 13:34:14 +01:00
edfef444fb revent: Updated WA to use the new revent
- Updated the revent parser to handle the new revent format.
- Updated the revent parser to expose device info and recording
  metatdata.
- The parser can now be used in streaming and non-streaming mode (stream
  events from the file as they are being accessed, or read them all in
  at once).
- -g option added to "record" command to expose the gamepad recording
  mode.
2016-10-26 13:33:54 +01:00
3a7a5276e4 revent: added gamepad recording + major refactor
- Added support for gamepad recording. This type of recording contains
  only the events from a gamepad device (which is automatically
  identified). The details of this devices are collected and stored as
  part of the recording. On playback, uinput is used to create a virtual
  gamepad and replay into it.
- A "mode" field has been added to the recording format to help
  distinguish between the normal and gamepad recording types.
- A field for the total number of input events has been added before the
  start of the event stream (after the device description).
- The structure of revent code has undergone a major overhaul to improve
  maintainability and robustness.
- More detailed "info" command output.
- Updated Makefile to support debug/production builds.
2016-10-26 13:17:07 +01:00
f179b09978 Merge pull request from marcbonnici/revent
ReventWorkload: Corrected mistake in screen capture argument
2016-10-26 12:00:50 +01:00
620fbfdd2a ReventWorkload: Corrected mistake in screen capture argument 2016-10-26 11:56:03 +01:00
4213e8e7d1 Merge pull request from marcbonnici/revent
ReventWorkload fixes and enhancements
2016-10-26 11:25:46 +01:00
9fffa7958a ReventWorkload: State detection fixes
- Corrected code highlighting and phase names in documentation
- Fixed check_states paremeter not being honoured
- Moved state dependencies check to happen earlier in execution
  and to be a user facing error
2016-10-26 11:16:49 +01:00
0f2bc17eca ReventWorkload: Added argument to take screen capture with revent record command
In order to use state detection with revent, a screen capture
is required for comparison. Added an argument to revent record command to
automatically record a screen capture after the recording is
complete.
2016-10-26 11:16:49 +01:00
558e40698b AndroidDevice: fixing UI hierarchy capture
- renamed the capture method from "capture_view_hierachy" to
  "capture_ui_hierarchy" to fix typo and make more descriptive.
- Change the file extension of the cature file to ".uix" because this is
  the extension uiautomatorviewer looks for.
2016-10-17 13:49:19 +01:00
41b52178bb pylint fixes. 2016-10-17 11:02:41 +01:00
8aa1bdc63d AndroidDevice: correctly handle None output on get_pids_of
It is possible that the command executed by get_pids_of() will return
None (in cases where there are no running processes with the specified
name and the grep call didn't find anything). If that happens, then the
subsequent call to split() failed (as that is not a method of None). To
avoid this, substitute an empty string instead.
2016-10-17 10:54:10 +01:00
8355fcf886 adb_shell: handle zero stdout on error
It looks like on recent systems, adb has started to correctly forward
stderr from the target device to stderr on the host (wereas in the past,
it got output to stdout on the host). This commit makes sure that
stderr gets correctly forwarded to the coller in cases where return code
checking was not enabled.
2016-10-17 10:49:53 +01:00
fa7d89d734 Merge pull request from jimboatarm/adobereader-s7fix
AdobeReader: Fails on S7 due to search icons being a different class.
2016-10-11 16:32:16 +01:00
4649fa13db AdobeReader: Fails on S7 due to search icons being a different class. Removed the class specifier 2016-10-11 13:25:35 +01:00
10dd2b304e ApkWorkload: ensure that the APK is always replaced and that a downgrade is allowed. 2016-10-10 13:15:24 +01:00
93fbb7282a AndroidDevice: added support for downgrade when installing an APK
Adds support for passing -d option to "pm install", which allows
installing an APK when a newer version of the package is already present
on the device.
2016-10-10 12:55:14 +01:00
edc26fe75c vellamo: fixing capitalization in automation
Capitalization for the "LET'S ROLL" button text was incorrect in the
automation code. This has not caused issues up to this point, but it
seems the button is no longer being found in the latest AOSP. This
commit corrects the capitalization.
2016-10-07 17:21:56 +01:00
6aecf1b35e Merge pull request from jimboatarm/reader-workload
Reader Workload: The Adobe Reader workflow carries out typical…
2016-10-05 08:30:57 +01:00
4c5e008609 Reader Workload: The Adobe Reader workflow carries out typical productivity tasks.
Conform to code style of other workloads.

Changed search strings to be a list. Allows user the ability to search for 1 or more search terms.

Renamed Reader to AdobeReader. Removed sleep and now detect and wait for searchicon
2016-10-04 16:59:22 +01:00
5bed658045 Merge pull request from jimboatarm/youtube-codetidy
Youtube: Codetidy to conform with the other workloads
2016-10-03 14:33:08 +01:00
8ac5657993 Merge pull request from jimboatarm/slides-codetidy
GoogleSlides: Code tidy, to conform with the other workloads.
2016-10-03 14:09:42 +01:00
fc26daecfc Merge pull request from jimboatarm/skype-codetidy
Skype CodeTidy to conform with the other workloads
2016-10-03 13:44:02 +01:00
0232341445 Merge pull request from jimboatarm/googlephotos-cropspeedchange
GooglePhotos: Change step value for crop operation to speed up workload
2016-10-03 13:25:45 +01:00
3b052cc619 Merge pull request from marcbonnici/revent
revent: Removed redundant android code
2016-09-30 14:33:52 +01:00
3a9505d54e revent: Removed redundant android code 2016-09-30 14:25:11 +01:00
4e94ff9ed7 Skype CodeTidy to conform with the other workloads
Dont double click if the confirm icon appears
2016-09-29 17:29:21 +01:00
c47ae5cfcf Youtube: Codetidy to conform with the other workloads 2016-09-28 14:39:53 +01:00
ce11b94f28 GoogleSlides: Code tidy, to conform with the other workloads. 2016-09-28 13:02:49 +01:00
765fdd7cbb GooglePhotos: Change step value for crop operation to speed up workload. 500 is too slow and not realistic of real user behaviour.
Image order not guaranteed. Changed workflow to use subfolders to guarantee ordering and have same action be performed on the same image. As a result, swipe gestures are no longer applicable

Colour change was using clicks. Now uses drags. This is more reliable across devices
2016-09-28 09:58:22 +01:00
77d724efa3 Merge pull request from ep1cman/install_fix
ApkWorkload: Fixed replacing apps on a device
2016-09-26 17:00:39 +01:00
acb9dd61e7 ApkWorkload: Fixed replacing apps on a device
Previously if trying to downgrade an app using the `-r` option of
`adb install` the `INSTALL_FAILED_VERSION_DOWNGRADE` error would occur.
The app is now uninstalled first to prevent this.
2016-09-26 16:53:03 +01:00
cc7684986a Merge pull request from marcbonnici/master
Skype: Added check for update popup.
2016-09-23 11:42:43 +01:00
e69aea4e69 Skype: Added check for update popup.
Since there has been an update to the skype app, there was now a
update prompt preventing test from running. Now checks for the
prompt on older versions of skype and dismisses it if present.
2016-09-23 11:18:40 +01:00
2b6f036d9a Merge pull request from jimboatarm/skype-codetidy
Skype: Codetidy, no functional changes
2016-09-22 17:28:25 +01:00
5738d19114 Skype: Codetidy, no functional changes. Make voice action default in code, move private function to bottom. 2016-09-22 16:52:39 +01:00
53ae47bff3 Merge pull request from marcbonnici/master
ReventWorkload:Fixed revent workloads with multiple iterations
2016-09-22 11:29:19 +01:00
1c8e18bf36 ReventWorkload:Fixed revent workloads with multiple iterations
Since initilize only runs once per workload, we can't set variables required
for each iteration in initilize. Revent workload was setting its file paths
in initilize, now moved to setup.
2016-09-22 11:26:25 +01:00
5dbf7e7d38 Merge pull request from jimboatarm/googlephotos-codetidy
GooglePhotos: Reorder functions and relabel ActionLogger tags
2016-09-20 12:48:45 +01:00
a2945d58cb Reorder functions and relabel ActionLogger tags. No functional changes made to actual workload run 2016-09-20 11:15:40 +01:00
8727fe514a Merge pull request from jimboatarm/googleplaybooks-gesturefix
GooglePlayBooks: Reorder so that the gesture test happens after selec…
2016-09-20 10:55:57 +01:00
6465e732fd Merge pull request from ep1cman/apk_ver_fixes
Redone APK file resolution
2016-09-20 10:50:29 +01:00
f9ec869c7b Revert "Updated workload versions to match APK files"
This reverts commit b426e00f2f.
2016-09-20 10:47:57 +01:00
1bbd3ef87a Revert "workloads: Fixed versions to be backward compatible"
This reverts commit 8608c3b747.
2016-09-20 10:47:57 +01:00
486ade6499 ApkWorkload: Reworked APK Resolution.
APK Resolution is now handled a bit differently to try maximise the likelyhood
of a workload running.

Like before `force_install` will always try to install the host version, if it
is not present or is not a correct version, it will error.

`check_apk` has changed so that when it is `True` it will prefer to use the host
side APK. If it is not there, or not a suitable version and/or abi and the target
already has a correct version of the app, the target app will be used. When it is
to `False` WA will prefer the target version of the app so long as it is a valid
version, if it is not then it will fallback to the host side APK.
2016-09-20 10:47:57 +01:00
1a23bd03a2 runner: Some types of exceptions will no longer take screenshots or dump UI hiarchy
For resource or Host errors (error which are not caused by the target).
the runner will no longer take screenshots ect as these are meaningless.
2016-09-20 10:13:14 +01:00
5018a1ec94 GooglePlayBooks: Reorder so that the gesture test happens after selecting a known chapter in the book. Previously the gestures could happen on any random page thus making the results not neccessarily comparable to another run. 2016-09-20 10:10:21 +01:00
fe58245843 Merge pull request from jimboatarm/youtube-actionlogger-modified
Youtube: Changed actionlogger to measure different more relevant acti…
2016-09-19 17:36:39 +01:00
006bf6387f Merge pull request from jimboatarm/googleplaybooks-actionlogger-renametags
GooglePlayBooks: Modified ActionLogger tags and capture points
2016-09-19 17:34:52 +01:00
19569816d3 Youtube: Changed actionlogger to measure different more relevant actions. Also rearranged if statement for video_source so that the default is at the top. 2016-09-19 16:46:03 +01:00
1dfbaf4ebe GooglePlayBooks: Modified ActionLogger tags and capture points 2016-09-19 14:21:03 +01:00
5b7d61b4b9 Merge pull request from jimboatarm/googleslides-slidecount-fix
GoogleSlides workload did not do slide_count number of swipes in edit…
2016-09-19 13:40:08 +01:00
b5dc5b8648 GoogleSlides workload did not do slide_count number of swipes in edit mode. This fixes that. 2016-09-19 13:26:21 +01:00
2202326c02 Merge pull request from ep1cman/glb_bug
workloads: Fixed versions to be backward compatible
2016-09-13 11:47:14 +01:00
8608c3b747 workloads: Fixed versions to be backward compatible
In a recent commit workload versions were changed to match their APK versions.
This commit adds the old versions to the allowed versions and automatically
maps them onto the new values.
2016-09-13 11:07:18 +01:00
9afe084f2c Merge pull request from setrofim/master
Miscellaneous fixes
2016-09-13 10:26:51 +01:00
83ab1ac441 Merge pull request from jimboatarm/upstream-slides
Add Google slides workload
2016-09-13 10:24:19 +01:00
ea1d13c37f common/android: pep8 fixes
- added missing space between global definitions and a class
- added missing space for inline comment
2016-09-13 10:22:47 +01:00
20996e9a58 core: changing the time of constraint validation for params
Constraints and allowed values of Extension Parameters will now be check
when the Parameter value is set, rather than when validating the
extension. Mandatory status of a Parameter is still checked during
valudation.
2016-09-13 10:20:52 +01:00
3711f7316d cpustates: fixing stand-alone script with timeline option
When running the stand-alone cpustates script and specifying a timeline
file (which causes the corresponding reporter to be enabled), a
timeline report is generated in addition to the usual cpustates and
parallelism reports.

Up to this point, the main() of the stand-alone script was expecting
exactly two reports and so it crashing when running with the timeline
option. This commit fixes this case.
2016-09-13 10:16:25 +01:00
d279cc7453 Add Google Slides workload 2016-09-12 17:57:41 +01:00
f6b8fd3f4b Ignore exception for non-fatal permission grant failure 2016-09-09 23:22:38 +01:00
ff2f88fbd7 Merge pull request from jimboatarm/googlephotos_uxperf
Add googlephotos workload
2016-09-09 14:26:46 +01:00
96f4ade874 Add googlephotos workload 2016-09-09 09:56:15 +01:00
ac0256e377 Merge pull request from jimboatarm/googleplaybooks_fix
Updates and fixes for googleplaybooks workload
2016-09-08 15:50:17 +01:00
793af6253f Merge pull request from jimboatarm/skype_uxperf
Add Skype workload
2016-09-08 13:34:57 +01:00
5ef7d2dd44 Remove skypevideo workload
The original skypevideo workload has now been replaced with the newer
skype workload.
2016-09-07 16:51:40 +01:00
cf8cb5bfab Add Skype workload 2016-09-07 16:45:11 +01:00
9376c6875b ApkWorkload extension support
- Allow disabling main activity launch in setup (required for some apps)
- Parameterise clear data on reset (default behaviour unchanged)
2016-09-07 16:45:07 +01:00
a6347f5833 Merge pull request from ep1cman/master
Workloads: Fixed issues with calling super
2016-09-06 10:16:08 +01:00
38a7e01e83 Workloads: Fixed issues with calling super
Super works by having a iterator of parent classes to ensure each is called
once and only once. WA calls some parent methods in classes with multiple
inheritenceconditionally so calls them directly instread. This breaks super
which ends up calling some methods multiple times.

To work around this until workloads are reworked to use composition rather than
inheritance, all classes that that subclass `Workload` directly no longer use
`super`.
2016-09-06 10:11:09 +01:00
e18366b3f8 Add support for chrome books to googleplaybooks workload
Accommodate layout changes in googleplaybooks on chrome book devices
when accessing the action bar menu in the app.
2016-09-05 17:15:49 +01:00
b9701201a3 Merge pull request from jimboatarm/upstream-youtube
Add Youtube workload
2016-09-05 15:37:47 +01:00
441ba974b7 Youtube workload 2016-09-05 15:03:53 +01:00
a33df50ce8 Use new AndroidUxPerformance class in googleplaybooks
Utilise new convenience method for checking for an valid internet
connection and set the min_apk_version within the AndroidUxPerformance
class.
2016-09-05 14:56:14 +01:00
52d4635fe8 Improve logic for scrolling during book search 2016-09-02 15:29:28 +01:00
14924ec6f4 Remove hardcoded package name from googleplaybooks workload 2016-09-02 15:29:28 +01:00
3d610788a3 Merge pull request from jimboatarm/check_app_version_uxperf
Add check_app_version method to ApkWorkload
2016-09-02 11:59:08 +01:00
1986511ae8 Add check_app_version method to ApkWorkload
Implement new method to enforce that a valid apk version is used to run
the workload. Based on a min and max range of apk versions tested
during development.
2016-09-02 11:56:40 +01:00
175e7f3cc0 Merge pull request from jimboatarm/workload-check-internet
Add network check methods to Device and Workload classes
2016-09-02 10:35:01 +01:00
392a3f1600 Add network check methods to Device and Workload classes
- Device subclasses should provide their own implementation.
    Default behaviour is to raise a `NotImplementedError`
  - Workload subclasses can set `requires_network` to `True` and
    network connectivity check will be performed during `setup()`
2016-09-02 10:33:18 +01:00
b5c0bdb0eb Merge pull request from jimboatarm/android_uxperf_workload
Android uxperf workload
2016-08-31 15:02:57 +01:00
502b0ed4b3 Add package name to uiautomator params in AndroidUxPerfWorkload
The package name is common to all workloads that inherit from this
class and is used when locating UI elements.
2016-08-31 14:44:21 +01:00
cab9d918ab Move uiautomator params in AndroidUxPerfWorkload
uiautomator parameters are set per instance of a workload and not per
iteration. Move uiautomator parameter assignment from setup() to
validate().
2016-08-31 14:43:33 +01:00
e686e89b39 Merge pull request from jimboatarm/broadcast_media_mounted
Add broadcast_media_mounted method to android device
2016-08-31 11:43:42 +01:00
b510b31052 Add broadcast_media_mounted method to android device
New method to force a re-index of the mediaserver cache for the
specified directory. Used in workloads that require external media files
as dependencies.
2016-08-31 10:24:06 +01:00
5b59d101ef Merge pull request from ep1cman/cleanup
Cleanup
2016-08-26 17:32:50 +01:00
7713f02252 Execution: Added a clean_up global config to delete WA files from devices
Adds a WA configuration point `clean_up` that will delete the WA binaries
directory  and the WA working directory from a device at the end of a WA run.
2016-08-26 17:25:11 +01:00
0a2afdfd84 AndroidDevice: Added -rf to delete_files
This allows it to delete folders and makes it consistend with LinuxDevice.
2016-08-26 17:13:21 +01:00
530714c61c Merge pull request from jimboatarm/uxperf_workload_class
Add new AndroidUxPerfWorkload class
2016-08-26 13:46:25 +01:00
67f418f79f Add new AndroidUxPerfWorkload class
Create a new workload class to encapsulate functionality common to all
uxperf workloads.
2016-08-26 12:22:39 +01:00
64860a2d1a Merge pull request from ep1cman/dependencies
pylint fixes
2016-08-25 14:25:42 +01:00
f57dd83d1a pylint fixes 2016-08-25 14:20:10 +01:00
3782a33060 Merge pull request from ep1cman/version_check_fixes
Version check fixes
2016-08-24 16:01:18 +01:00
8e27794124 Added a script to check APK/Workload versions for inconsistencies 2016-08-24 15:48:22 +01:00
9d4aa4983a antutu: Fixed setting permissions
It has been observed on some devices that the FINE_LOCATION premissions is required
for antutu to run without asking for permissions at run time but this was not listed
in the APK manifest. This caused issues on devices were only the permissions in the
manifest can be granted. This commit sliences any error when trying to set this permission
as well as only trying only on Android 6+
2016-08-24 14:36:00 +01:00
b426e00f2f Updated workload versions to match APK files
Some workloads presented a different version than what was in the APK file.
With the changes introduced in bb33123 several workloads broke.
2016-08-24 14:33:18 +01:00
07d34e5615 ApkWorkload: Moved APK resolution into setup
Previously if you had multiple versions of the same workload in one
agenda only the first one would work, the others would fail to find
their APK.
2016-08-24 14:28:53 +01:00
b1ae5a5465 Merge pull request from setrofim/master
ssh: fixing rasing of CalledProcessErrorWithStderr
2016-08-23 17:26:07 +01:00
4ea4bc8631 ssh: fixing rasing of CalledProcessErrorWithStderr
CalledProcessErrorWithStderr is a subclass of CalledProcessError that
also takes stderr output. Both that and normal output must be passed as
keyword arguments. They were being passed as keyword arguments inside
_scp() of SshConnection, causing cryptic errors to appear.

Additionally, "output" was not being properly poped off before invoking
super's init.
2016-08-23 17:22:02 +01:00
fe259dca05 Merge pull request from jimboatarm/googleplay_uxperf
Add UxPerfUiAutomation and googleplaybooks workload
2016-08-09 13:49:02 +01:00
86f3066f56 Add unsupported package check to AndroidUiAutoBenchmark
Add method to automatically check against a dictionary of known package
versions that don't work well with AndroidUiAutoBenchmark workloads.
Raises an exception if found.
2016-08-09 12:08:28 +01:00
0f579e18b3 Add googleplaybooks workload 2016-08-09 12:08:20 +01:00
25172fb027 Add UxPerfUiAutomation class
UxPerfUiAutomation contains methods specific to UX performance testing.
2016-08-09 09:56:04 +01:00
550a0db61a Rename dumpsys_enabled parameter to markers_enabled
Change parameter name for enabling markers to better reflect its
purpose. The old name was a misnomer.
2016-08-09 09:56:04 +01:00
73c2609a72 Fix message regex in uxperf result processor
The logcat output differs between devices. Modify the regex pattern to
accommodate different output formats when matching UX_PERF markers.
2016-08-09 09:56:04 +01:00
1ec7961b0e Merge pull request from drcef/master
Implemented visual state detection functionality for revent workloads
2016-08-05 11:57:59 +01:00
01f2a5f412 Implemented visual state detection functionality for revent workloads
- Added statedetect.py in utils which is a standalone module that
    contains all the methods needed for state detection

  - Modified the setup() and run() methods of the GameWorkload class
    in common/android/workload.py to have a parameter that enables
    state checks and run the check after setup and run if requested.

State detection uses the template matching method available in
OpenCV to determine the state of the workload by detecting
predefined unique elements on a screenshot from the device.
2016-08-05 10:09:18 +01:00
480a054860 Merge pull request from ep1cman/master
RunConfiguration: Fixed disabling of instruments in workload specs
2016-08-04 16:18:52 +01:00
e9ba9352a6 RunConfiguration: Fixed disabling of instruments in workload specs 2016-08-04 16:16:53 +01:00
0a3ff099c0 Merge pull request from jimboatarm/mdzj/upstream-get-assets
Add script to get external assets for workloads
2016-08-04 15:46:16 +01:00
75cc5854bf Add script to get external assets for workloads 2016-08-04 13:59:12 +01:00
77aaa0b849 Merge pull request from jimboatarm/dump_hierarchy_uxperf
Dump hierarchy view on error
2016-08-03 09:57:09 +01:00
0945dd6ba4 Dump hierarchy view on error
Dump window hierarchy view from uiautomator to a file when WA fails
during execution. Note: the xml file are pre-formatted after dump.
Implementation specific to android.device.
2016-08-02 16:47:24 +01:00
4c94ba43ac Merge pull request from jimboatarm/remove-old-apk-permissions
permission grant for API 23 and above
2016-07-29 16:33:59 +01:00
efae2e8c32 Android permission grant for API 23 and above
Issue: On some devices, _grant_requested_permissions may throw an
error when trying to grant permissions that were already granted
at install time using 'adb install -g'.

Fix: Surround permission grant method for API 23+ with try/except

Issue: Currently, _grant_requested_permissions skips all lines after
the first line not starting with 'android.permission'. This causes
a problem for apps where some required permissions appear after a
non-matching line e.g. Google Slides.

Fix: Don't break on non-matching line until end of section is reached
2016-07-29 16:27:29 +01:00
59874b862d Merge pull request from jimboatarm/fps_util_uxperf
Additional changes to FpsProcessor, fps instrument and uxperf result processor
2016-07-27 14:56:14 +01:00
da19859c25 Add logging and exception handling to uxperf result processor
The uxperf result processor now provides warnings for unmatched UX_PERF
markers when running the fps instrument. Previously unmatched markers
resulted in an exception being thrown. Includes additional logging for
debugging purposes.
2016-07-27 14:50:24 +01:00
d87e425c24 Merge pull request from jimboatarm/network_check_uxperf
Add network connectivity check for devices
2016-07-27 11:59:57 +01:00
2872080d1a Add network connectivity check for devices
Add a general check that pings a IP address rather than checking the
status of dumpsys wifi due to the fact that not all devices are
connected via wifi. Intended for workloads that require an internet
connection to operate.
2016-07-26 16:30:06 +01:00
625a3a39a5 Add dumpsys_period parameter to fps instrument
Add a new parameter to fps instrument to specify the time period between
calls to ``dumpsys SurfaceFlinger --latency`` in seconds when collecting
frame data. A lower value improves the granularity of timings when
recording actions for UX Performance metrics.
2016-07-26 11:30:34 +01:00
aa2d187c4d Fix for FpsProcessor logic in utils module
- Add requirement on filtered_vsyncs_to_compose for total_vsync metric
- Remove misleading comment in class description
2016-07-26 11:29:51 +01:00
b80e5dc52e Merge pull request from jimboatarm/baselib_uxperf
Extensions to baselib for UX Performance
2016-07-26 11:28:57 +01:00
2208d45bfb Add further convenience methods to BaseUiAutomation
Convenience methods to make it easier to get UiObjects and perform
UiDevice based gestures and operations.
2016-07-26 10:34:04 +01:00
51e4e71931 Upgrade Android API level from 17 to 18
Upgrade API level for BaseUiAutomation from 17 -> 18 and update
dependent workloads accordingly.
2016-07-26 10:30:15 +01:00
0388fa6f36 Minor code maintenance for base class BaseUiAutomation
- Rename inconsistently named variables
- Avoid long wrapped lines where possible
- Fix whitespace around operators
2016-07-26 08:59:17 +01:00
ee7c04a568 Merge pull request from ep1cman/revent_fixes
Pylint fixes
2016-07-21 16:47:14 +01:00
9707aa6237 Pylint fixes
Pylint now checks for trailing new lines, this commit fixes them.
2016-07-21 16:40:26 +01:00
019ee34c0d Merge pull request from ep1cman/revent_fixes
Revent fixes
2016-07-21 15:43:55 +01:00
873bdf0bc7 revent: replay and record fix + reorganisation
The two commands now always copy over revent.

Reoraganised the commands to use a common base class.
2016-07-21 15:42:12 +01:00
54c409ce6f revent: Fixed magic check
A null character was not being added to the end of the string.
2016-07-21 15:42:11 +01:00
a2d0747b4c Merge pull request from ep1cman/revent_fixes
revent: Fixed dump command segfault
2016-07-19 16:54:53 +01:00
25eac432c9 revent: Added revent file structure to documentation 2016-07-19 16:52:12 +01:00
dd61f99785 revent: Updated resource getters to check if a file is actually a recording 2016-07-19 16:48:13 +01:00
164f207084 revent: Timeout is now based on recording duration
The revent file is now parsed and the duration of the recording is calculated.
This duration + 30 seconds is now used for the timeout for revent.
2016-07-19 16:48:13 +01:00
cb01b0c9a9 utils/revent: Added revent recording parser
revent binary recordings can now be parsed and used within WA.
2016-07-19 16:48:13 +01:00
139a0698c9 revent: Added "magic" and file version to revent files.
revent files should now start with "REVENT" followed by the file format
version.
2016-07-19 16:48:13 +01:00
259b813a96 revent: Various fixes.
revent:
    - Fixed 32-bit/64-bit compatibility by no longer "long" for timestamps
    - Removed superfluous code
    - SIGTERM is now handled only while waiting for a file not while processing one
    - Added '-s' to docs
    - Fixed path_buff size

Record Command:

    - Removed timeout in command as -s is specified.
    - Previously the command would send SIGTERM to revent but not wait for it to terminate.
      This would result in the pulled recording missing its send. This has now been fixed.

Replay Command:
    - Added more logging
2016-07-19 16:11:42 +01:00
299b28b3c1 Merge pull request from setrofim/master
resource getters: weaken File to also resove to directories
2016-07-15 16:07:49 +02:00
ece33c1d68 resource getters: weaken File to also resove to directories
Because UNIX tells us that "everything is a file".
2016-07-15 15:05:19 +01:00
f68cf4e317 Merge pull request from jimboatarm/marker_api
Add per-action instrumentation for UX performance
2016-07-15 11:15:46 +02:00
c49c5c4121 Add per-action instrumentation for UX performance
- Implement a new Marker API in BaseUiAutomation so workload can
  generate start and end markers with string name. Outputs to logcat.

- Document the Marker output log format in the WA documentation

- Create a results processor to take existing instrument fps logs and
  parse them based on the workload markers. Produce per-action fps
  metrics.

- Add simple timing results based on the workload markers
2016-07-14 13:49:39 +01:00
b8d7956d4c Move processing logic in fps instrument to utility file
Processing logic for frame statistics can be moved out of fps instrument
to a new utility file. This will allow result processors to use the same
logic to produce frame statistics on a subsection of the data
produced by the fps instrument.
2016-07-14 13:49:39 +01:00
fee872585f Merge pull request from mdigiorgio/camerarecord-slowmo
camerarecord: add possibility to select slow_motion recording mode
2016-07-13 17:14:07 +01:00
2dd3a2ba4d camerarecord: add possibility to select slow_motion recording mode
Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
2016-07-13 16:40:39 +01:00
662033399f Merge pull request from jimboatarm/upstream-apk-check
Apk version check
2016-07-12 17:53:01 +01:00
bb33123b17 Check APK version and ABI when installing
- Check the APK's versionName property against the workload's
  expected version if specified
- If workload specifies check_abi param, try to get APK from
  ABI-specific path on the host
- Add variant_name param to APK resource-getter for backwards
  compatibility of dex2oat and peacekeeper
2016-07-12 17:02:17 +01:00
fab6a977aa Properly replace APK during adb install
Issue: For certain installation errors, it is possible for WA to
 incorrectly report that an APK was reinstalled while it actually
 wasn't, leading to bugs later on in the run.

Fix:
 - Add the '-r' flag to adb install when reinstalling, to make sure
   APK is replaced.
 - Add '-g' flag for API 23 and higher, to grant all permissions that
   would otherwise be requested at runtime (similar to pre-API 23)
2016-07-12 13:08:28 +01:00
25dd6b71f3 Merge pull request from mdigiorgio/camerarecord-framestats
camerarecord: add frame stats collection through dumpsys gfxinfo
2016-07-11 15:43:13 +01:00
246416d4d2 Merge pull request from setrofim/master
file_poller fixes.
2016-07-11 14:56:01 +02:00
1fe037486f file_poller: added error checking and reporting
- Updated poller binary to propery check for errors (e.g. on attempting
  to open a file) and report them to stderr
- Updated the file_poller instrument to collect poller stderr output
  into a log file and to check the log for errors or warnings on
  completion of an iteration.
2016-07-11 13:55:11 +01:00
f27b500028 camerarecord: add frame stats collection through dumpsys gfxinfo
Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
2016-07-11 13:53:38 +01:00
5a780e8211 file_poller: fixed validation with Linux devices
- device.is_rooted check was being perfromed inside validate() which
  gets invoked before the device is connected. This worked for most
  Android devices, because connections is a no-op for them, however
  failed for Linux targets. The check is now performed inside
  initialize().
- Added _is_ready() check inside is_rooted to catch similar problems
  quicker in the future.
2016-07-11 13:23:15 +01:00
60ca0649ab Merge pull request from ep1cman/master
file-poller: Improved csv output
2016-07-11 11:21:45 +01:00
dbda128813 file-poller: Improved csv output
All ',' and '\n' will now be stripped from the files contents so it doesn't
effect csv formatting

Also fixed some whitespace
2016-07-11 11:06:57 +01:00
ff7a0626ce Merge pull request from per-mathisen-arm/master
Fix a frequently repeated typo
2016-07-11 09:09:13 +01:00
9a94c59605 Merge pull request from mdigiorgio/geekbench-output
geekbench: fix output files listing
2016-07-11 09:08:53 +01:00
d3dd9c849a geekbench: fix output files listing
After running the benchmark, when collecting the output files the execution
fails because the split('\n') call, used for creating a list of output files,
returns an empty string as last element. The empty string makes the pull command
fail because file '' doesn't exist on the target device.

Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
2016-07-08 11:59:51 +01:00
12a78ce291 Fix a frequently repeated typo 2016-07-08 10:16:47 +02:00
c8a735e298 sysbench: adding arm64 binary 2016-07-01 17:35:19 +01:00
071bf9fba7 Merge pull request from ranjeetkumar/master
Permission granted for generic browser
2016-06-29 13:40:46 +01:00
ef919a0fa9 Merge pull request from setrofim/master
LinuxDevice: error output for pull/push_file
2016-06-29 13:39:02 +01:00
88b18dda07 Permission granted for generic browser 2016-06-29 17:57:25 +05:30
242df842bc LinuxDevice: error output for pull/push_file
Standard string representation of a subprocess.CalledProcessError does
not include the output of the command, so it was not previsouly included
in the resulting DeviceError. This commit ensures that the output is
propagated, regardless of whether it came from stdout or stderr of the
underlying process.
2016-06-28 13:48:48 +01:00
a6355885fc Merge pull request from ep1cman/fixes
AndroidDevice & BaseLinuxDevice: minor parameter changes
2016-06-21 14:57:05 +01:00
77a44f11c6 AndroidDevice & BaseLinuxDevice: minor parameter changes
Moved ``working_directory`` parameter to BaseLinuxDevice.

Changed the default ``binaries_directory`` for AndroidDevice to allow
WA binaries to be easily separated.
2016-06-21 14:55:02 +01:00
afeb726d53 energy_model: only set "ui" runtime parameter for ChromeOS
energy_model instrument generates job specs during the run. One of the
things it does is set "ui" runtime parameter to "off". This parameter
only exists for ChromeOS devices. This commit ensure that the parameter
is not set when running on any other device.
2016-06-21 09:14:12 +01:00
7904e6b562 Merge pull request from ep1cman/fixes
sysfs_extractor & cpufreq: Fixed error when tar.gz file already existed
2016-06-20 10:13:38 +01:00
224b973ace sysfs_extractor & cpufreq: Fixed error when tar.gz file already existed
If the tar.gz already existed on the target device the instruments would
fail. This fix adds the "-f" option to gzip to force it to overwrite the
file.
2016-06-20 10:12:00 +01:00
8660d0f488 hwuitest: invoke executable via full path
Previously, the workload was invoking the executable via its name,
assuming that it will be in PATH. As WA's executables directory is not
in path, the invocation was failing. This commit saves the full path to
the installed executable and uses that instead.
2016-06-17 08:03:50 +01:00
be7aa3d379 recentfling: fixing uninstalling of binaries
Inconsistently, while install() for Android devices automatically
handles both APKs and executables appropriately, uninstall() only works
for packages. Changing to use uninstall_executable() for the scripts
deployed by recentfling.
2016-06-15 09:00:49 +01:00
8503fea0ee Merge pull request from ep1cman/release-notes
docs: Clarified documentation regarding binary dependencies
2016-06-14 11:18:25 +01:00
4a15a41cf8 docs: Clarified documentation regarding binary dependencies 2016-06-14 11:13:54 +01:00
3a90309383 Merge pull request from setrofim/master
bbench and recentfling fixes
2016-06-14 10:22:20 +01:00
b48e5ce58a recentfling: script deployment and PID file fixes
- Scripts are now deployed during via install() ensuring that they are
  executable.
- Handle the case where the PID file is delted before getting to
  process_results.
- Exposed the option to not start any apps before flinging via a
  parameter.
2016-06-14 10:21:06 +01:00
f33d6f4729 bbench: handle lack of results in logcat
- make sure results_list is always instatiated even if no metrics found;
  this would previously cause a "used before declaration" error
- Detect that no metrics were extracted from the log and raise a
  WorkloadError
2016-06-14 10:20:51 +01:00
6f8989a8ba setup.py: Updated url to be a valid URI
New PyPI upload APIs were complaining.
2016-06-10 15:56:19 +01:00
a826b661f4 Version bump 2016-06-10 14:26:32 +01:00
43f4e52995 Merge pull request from ep1cman/release-notes
Documentation changes & Removing apk_version
2016-06-10 13:22:11 +01:00
23b3b165d5 docs: Change log & updates 2016-06-10 13:17:10 +01:00
2f87e126f0 apk_version: Removed instrument
APK versions are now added as result classifiers:
48259d872b
2016-06-09 13:55:27 +01:00
59d74b6273 Merge pull request from ep1cman/release-notes
servo_power: Added check for device platform.
2016-06-08 11:16:14 +01:00
7b92f355c8 netstat: Changed exception type & typo fix 2016-06-08 11:13:35 +01:00
982069be32 servo_power: Added check for device platform.
Now checks to see if the device is running chromeOS.
2016-06-08 11:10:53 +01:00
63ff8987ea Merge pull request from ep1cman/cpustates
cpustates
2016-06-06 17:12:12 +01:00
f276d4e39f cpustates: Added the ability to configure how a missing start marker is handled.
cpustates can now handle the lack of a start marker in three ways:

 - try: If the start marker is present only the correct section of the trace
        will be used, if its not the whole trace will be used.
 - error: An error will be raised if the start marker is missing
 - ignore: The markers are ignored and the whole trace is always used.
2016-06-06 17:09:48 +01:00
1811a8b733 PowerStateProcessor: Added a warning when no stop marker is encountered
PowerStateProcessor will now stop itrerating over events when it finds
a stop marker. If it does not find a stop marker it will log a warning.
2016-06-06 17:03:56 +01:00
0ae03e2c54 PowerStateProcessor: Exceptions no longer stop processing
If an exception is raised inside a generator it cannot be continued.
To get around this exceptions are now caught and later output via the
logger.

Also added logger setup when running cpustates as a standalone script
2016-06-06 16:28:07 +01:00
c423a8b4bc Utils.misc: Added memoised function decorator
This allows the return value of a function to be cached so that
when it is called in the future the function does not need to
run.

Borrowed from: https://github.com/ARM-software/devlib
2016-06-06 16:28:07 +01:00
c207a34872 cpustates: Now shows a warning when it fails to nudge a core.
Before WA would raise a error message that wasn't very clear.
Now when cpustates tries to nudge cores and and error occurs it
will only show a warning (which promts users to check if the cpu is
hot plugged out) and keep going with the reset of the run without
causing errors in other WA extensions.
2016-06-02 15:14:03 +01:00
2cb40d3da6 Merge pull request from ep1cman/master
Revent fixes
2016-06-01 17:04:46 +01:00
18d1f9f649 ReventWorkload: Now kills all revent instances on teardown
Previously revent would be left running if a run was aborted.
2016-06-01 16:47:01 +01:00
17ce8d0fe9 Revent: Device model name is now used when searching for revent files
Previously the WA device name was used when searching for revent files.
Since most were `generic_android` this made it difficult to keep revent
files for multiple android devices. Now it the device model is used instead.

If a file with the device model is not found it will fall back to the WA
device name.
2016-06-01 16:47:01 +01:00
ac03c9bab4 Merge pull request from ep1cman/master
LinuxDevice fixes
2016-06-01 14:14:13 +01:00
8bdffe6f9c LinuxDevice: Removed has_root method
Was not used anywhere and is_rooted should be used instead
2016-06-01 14:13:37 +01:00
2ff13089fd LinuxDevice: kick_off & killall will now run as root on rooted devices by default
kick_off has been changed to behave the same as AndroidDevice.

Said changes caused kill all to fail on rooted devices. Killall will now
behave in the same way as kick_off, if specifically told to (or not to)
run as root it will. Otherwise it will run as root if the device is rooted
2016-06-01 13:50:59 +01:00
772346507c Merge pull request from ep1cman/servo
servo_power: Added support for chromebook servo boards
2016-05-27 16:16:49 +01:00
0fc88a84be servo_power: Added support for chromebook servo boards
Servo is a debug board used for Chromium OS test and development. Among other uses, it allows
access to the built in power monitors (if present) of a Chrome OS device. More information on
Servo board can be found in the link bellow:

 https://www.chromium.org/chromium-os/servo

based on: 03ede10739
and: 9a0dc55b55
2016-05-27 16:09:08 +01:00
6e4f6af942 Merge pull request from ep1cman/poller
Poller: Added an instrument to poll files and output a csv of their v…
2016-05-26 16:33:59 +01:00
c87daa510e Poller: Added an instrument to poll files and output a csv of their values 2016-05-26 16:32:58 +01:00
5e1c9694e7 Merge pull request from setrofim/master
list_or_string: ensure that elements of a list are always strings
2016-05-26 16:07:22 +01:00
a9a42164a3 list_or_string: ensure that elements of a list are always strings 2016-05-26 16:05:43 +01:00
0d50fe9b77 AndroidDevice: kick-off no longer requires root
kick off will now use root if the device is rooted or if manually
specified otherwise its run without root.
2016-05-26 10:29:21 +01:00
e5c228bab2 Merge pull request from ep1cman/camera_update
cameracapture & camerarecord: Fixed parameters
2016-05-25 09:49:58 +01:00
7ccac87b93 cameracapture & camerarecord: Fixed parameters
Parameters were not being passed to the UI automation properly
2016-05-25 09:49:21 +01:00
24a2afb5b9 Merge pull request from ep1cman/vellamo-update
Vellamo update
2016-05-24 13:01:31 +01:00
9652801cce vellamo: Fixed geting values from logcat
The previous method of getting results out of logcat does not work
if the format of logcat changes.
2016-05-24 13:00:10 +01:00
881b7514e2 Merge pull request from ep1cman/buildprop
AndroidDevice: Improved gathering of build props
2016-05-24 12:56:22 +01:00
17fe6c9a5b AndroidDevice: Improved gathering of build props
These are now gathered via `getprop` rather than trying to parse the
build.prop file directly.

This fixes issues with build.prop files that have imports.
2016-05-24 12:55:33 +01:00
f02b6d5fd9 vellamo: Added support for v3.2.4 2016-05-24 09:57:38 +01:00
eaf4d02aea Merge pull request from chase-qi/add-blogbench-workload
workloads: add blogbench workload
2016-05-24 09:55:37 +01:00
56a4d52995 workloads: add blogbench workload
Blogbench is a portable filesystem benchmark that tries to reproduce the
load of a real-world busy file server.

Signed-off-by: Chase Qi <chase.qi@linaro.org>
2016-05-24 16:49:19 +08:00
ec5c149df5 Merge pull request from chase-qi/add-stress-ng-workload
workloads: add stress_ng workload
2016-05-24 09:45:35 +01:00
c0f32237e3 Merge pull request from ep1cman/camera_update
cameracapture & camerarecord: Updated workloads to work with Android M+
2016-05-16 17:28:39 +01:00
5a1c8c7a7e cameracapture & camerarecord: Updated workloads to work with Android M+
The stock camera app as of Android M has changed. This commit updates
the ui automation to work with this new app. As part of this change
it was required to bump the API level of the ui automation to 18.

Also made the teardown of the capture workload close the app like the
record workload.
2016-05-16 17:25:50 +01:00
46cd26e774 BaseUiAutomation: Added functions for checking version strings
Added splitVersion and compareVersions functions allow versions strings
like "3.2.045" to be compared.

Also fixed the build script to now copy to the correct folder
2016-05-16 17:22:09 +01:00
544c498eb6 UiAutomatorWorkload: Added quotes around uiautomator parameters
Some characters would be interpreted by the shell thus breaking the
command. Adding quotes around the parameters solved this.

N.B Space still needs to be replaced.
2016-05-16 16:19:57 +01:00
5ad75dd0b8 workloads: add stress_ng workload
stress-ng will stress test a computer system in various selectable ways.
It was designed to exercise various physical subsystems of a computer as
well as the various operating system kernel interfaces.

Signed-off-by: Chase Qi <chase.qi@linaro.org>
2016-05-13 19:35:26 +08:00
b2248413b7 Merge pull request from ep1cman/master
cpustates: Fix for error when trying to use cpustates with hotplugged…
2016-05-13 11:35:45 +01:00
9296bafbd9 Merge pull request from ep1cman/juno-fixes
hwmon & adb fixes
2016-05-10 09:49:33 +01:00
8abf39762d hwmon: Fixed sensor naming
Previously the sensor name was just appeneded to the end of the
previous sensors name.

Now the hwmon name is added as a classifier of the metric.
If the hwmon sensor has a label, the metric will use this for its name,
if it does not then the sensors kind and ID will be used e.g. temp3
2016-05-10 09:27:42 +01:00
87cbce4244 hwmon: Added allowed values to sensors parameter
Previously the sensor name was just appeneded to the end of the
previous sensors name.
2016-05-10 09:27:42 +01:00
ef61f16896 AndroidDevice: Fixed screen lock disable
Due to the previous commits, this command no longer works properly.

It turns out there is an issue with using multiple levels of escaping.
It seems that bash handles the backslashes and single quotes separately
incorrectly processing our escaping. To get around this we are writing the
sqlite command to a shell script file and running that.

This seems to be the only case in WA at the moment that requires this,
if more show up/when WA moves to devlib it should use the devlib shutil
mechanism.
2016-05-10 09:27:42 +01:00
e96450d226 adb_shell: Fixed getting return codes
They way we were attempting to get return codes before always gave
us a return code of the previous echo, therefore always `0`.

This commit adds the newline into the last echo.
2016-05-10 09:12:54 +01:00
2cf08cf448 Merge pull request from ep1cman/fixes
Added sqlite3 binary & changed kick_off signature
2016-05-09 17:36:04 +01:00
59cfd7c757 AndroidDevice: WA now pushes its own sqlite3 binary
Some device have the sqlite3 binary removed. WA will now check for
this and push its own binary if necessary.
2016-05-09 17:31:09 +01:00
d3c7f11f2d AndroidDevice: Changed kick_off signature to match BaseLinuxExamples 2016-05-09 17:06:08 +01:00
187fd70077 Merge pull request from setrofim/master
report_power_stats: number of entries returned always matches number of reporters
2016-05-09 10:23:05 +01:00
fe7f98a98b report_power_stats: number of entries returned always matches number of reporters
Previously, only reports that were generated were returned. With this
commit, there will be an entry for each active reporter in the returned
list. If a reporter did not produce a valid report, the entry will be
None.

This ensures consistent output, even if a run time issue causes a
reporter not to produce a report  (e.g. if cpufreq events were not
enabled).
2016-05-09 10:20:25 +01:00
66c18fcd31 cpustates: Fix for error when trying to use cpustates with hotplugged cores
It is not possible to read frequencies from a core that has been hotplugged.
The code will now set the current and max frequencies of hotplugged cores
to None.

This still doesn't work for devices that have dynamic hotplug enabled
2016-05-06 15:00:32 +01:00
5773da0d08 Merge pull request from setrofim/master
sysfile_getter/cpufreq: fix taball name
2016-05-06 13:54:53 +01:00
d581f1f329 sysfile_getter/cpufreq: fix taball name
Commit 724f6e590e changed sysfile_getter
behavior to first tar up copied files and then gzip them. Tarball name
needs to be updated to not include '.gz' extension.
2016-05-06 13:51:09 +01:00
f165969d61 Merge pull request from ep1cman/juno-fixes
Juno fixes
2016-05-04 11:57:56 +01:00
8dc24bd327 uboot: Now detects the U-Boot version to use correct line endings
Previously Linaro U-Boot releases had a bug where they used \n\r
as the line ending. This has now been fixed which caused
issues with WA. WA now detects the U-Boot version and uses the
coresponding line ending.
2016-05-04 11:54:29 +01:00
59066cb46d juno: Removed default bootargs
The default boot args have been removed since these cause issues with
the latest Linaro builds, which boot correctly without any bootargs.

Also made a regex string a raw-string.
2016-05-03 15:24:35 +01:00
6c4d88ff57 Merge pull request from setrofim/master
create command: fix example parameter name in templates
2016-04-20 14:45:16 +01:00
a40542d57b create command: fix example parameter name in templates
Parameter name in workload templates updated to be a valid identifier.
2016-04-20 14:43:07 +01:00
697aefc7bb ApkWorkload: clear app data on failed uninstall.
If uninstall fails, "pm clear" should be called to make sure that the
next time the app is launched it starts from a known state (which would
normally be ensured by the uninstall).
2016-04-19 16:43:42 +01:00
8bc71bb810 ApkWorkload: report correct apk verison on failed install
It's possible that there is already a version of an app on target that
differs form the version of the apk on the host. In such cases, WA will
usually try to uninstall the target version and install the host
version.

It's possible that the uninstall may fail. If that happens, it will be
reported as a warning but workload exectuion will proceed with the
target version. In this case, apk_version would have already been set to
that of the host apk. This change ensures that the APK version is
correctly set to the target version (the one that actually ran).
2016-04-19 16:33:37 +01:00
91210f26e9 RunCommand: WA no longer runs with no workloads specs
Previously if no worklaod specs were loaded, WA would still start instruments
and then go immediately to the teardown stage. This no longer happens.
2016-04-19 16:32:53 +01:00
44a49db04d glbcorp: pep8 fix
Added a missing blank line between method declaration and class
attribute definitions.
2016-04-15 16:39:24 +01:00
0bfa4bff3c Merge pull request from ep1cman/master
glbench updates
2016-04-14 16:41:26 +01:00
73aa590056 glbench: renamed start_activity to launch_package
To match changes made in: ff5f48b7e7
2016-04-14 16:36:37 +01:00
985b249a24 glbench: Fixed ending regex
Updated the regex that detected the end of the benchmark to match the new
logcat format.
2016-04-14 16:36:37 +01:00
f5e138bed0 Merge pull request from setrofim/master
boostrap: nicer error messages on config parasing.
2016-04-14 16:22:10 +01:00
b6c0e2e4fd boostrap: nicer error messages on config parasing.
- handle ValueError as well as SyntaxError from config parser
- Report source file in the error message
2016-04-14 16:18:31 +01:00
df8ef6be6b Merge pull request from mcgeagh/uxperf
CpuUtilisationTimeline added. This now will generate cpu utilisation …
2016-04-14 14:05:58 +01:00
8a3186e1c8 CpuUtilisationTimeline added. This now will generate cpu utilisation based on frequencies and a number of samples
Fixed error in percentage when frequency is 'None'. Now default to 0 in these cases

cpu_utilisation is now a separate parameter in cpustate. Now generates a floating point number representing the utilisation based on the maximum frequency of the capture. No longer performs averaging of values, this can be done as a post-processing step

cpu utilisation now based on the max cpu freq per core, not max captured freq overall
2016-04-14 14:03:28 +01:00
68043f2a52 Merge pull request from mcgeagh/fps-allviews
fps: Can now process multiple 'view' attributes
2016-04-14 13:57:28 +01:00
95bbce77a2 fps: Can now process multiple 'view' attributes 2016-04-14 13:12:39 +01:00
ec85f9f8a0 Merge pull request from setrofim/master
ApkWorkload: add package verison to the result as a classifer.
2016-04-14 11:35:49 +01:00
82e4998092 Deprecating apk_version instrument. 2016-04-14 11:33:54 +01:00
48259d872b ApkWorkload: add package verison to the result as a classifer. 2016-04-14 11:23:39 +01:00
8d13e1f341 Merge pull request from ep1cman/glbench_logcat_fix
glbench: Fixed updated logcat format
2016-04-13 16:46:09 +01:00
33ef949507 Merge pull request from mcgeagh/fps-fix
Only check for crashed content if crash_check is true.
2016-04-11 13:38:18 +01:00
68714e0e55 fps: Only check for crashed content if crash_check is true. 2016-04-11 12:01:12 +01:00
9ee1666a76 Merge pull request from ep1cman/master
SysfsExtractor & Busybox fixes
2016-04-07 10:31:31 +01:00
8dcdc9afe1 busybox: Rebuilt busybox binaries to prefer applets over system binaries
Busybox will now prefer to use its own built in applets before it tries
using the system binaries so that we are always running commands as expected.
2016-04-07 10:29:13 +01:00
724f6e590e SysfsExtractor: Now performs tar and gzip separately
On some devices there were permissions issues when trying to tar and gzip
the temp-fs in one command. These two steps are now done separately.
2016-04-07 10:29:13 +01:00
507090515b Merge pull request from jimboatarm/master
Fix to install APKs with whitespace in their path name
2016-04-06 10:56:58 +01:00
1dfbe9e44c Fix to install APKs with whitespace in their path name 2016-04-06 10:53:08 +01:00
d303ab2b50 Merge pull request from ep1cman/artem
ADB 1.0.35 support
2016-04-05 16:05:16 +01:00
b17ae78d6b adb_shell: Now handles return codes from ADB
As of ADB 1.0.35/Android N, it will return the exit code of the command that it runs
This code handles this scenario as before WA treated a return code from ADB as an
error with ADB.
2016-04-05 15:53:41 +01:00
391b0b01fc pylint/pep8 fixes
- android/workload: emoved an extra bank line between methods
- trace_cmd: define member attribute inside __init__
- adb_shell: ignore pylint warning about too many branches in this case
2016-04-05 11:36:39 +01:00
20861f0ee4 Merge pull request from jimboatarm/master
Fix for packages without launch activities
2016-04-05 11:00:50 +01:00
ff5f48b7e7 Fix for packages without launch activities
If the package has no defined launch activity you must call the
activity manager in a different way.
2016-04-05 10:24:42 +01:00
9a301175b0 glbench: Fixed updated logcat format
The old results looked like:
I/TfwActivity(30824):    "description": "",
I/TfwActivity(30824):    "elapsed_time": 62070,
I/TfwActivity(30824):    "error": "NOERROR",

The new format is:
04-04 11:38:04.144  1410  1410 I TfwActivity:    "description": "",
04-04 11:38:04.144  1410  1410 I TfwActivity:    "elapsed_time": 62009,
04-04 11:38:04.144  1410  1410 I TfwActivity:    "error": "NOERROR",
2016-04-04 17:33:48 +01:00
712c79020d Merge pull request from ep1cman/master
ResourceResolver: Show version number when resource wasn't found.
2016-03-30 11:05:21 +01:00
12dfbef76b ResourceResolver: Show version number when resource wasn't found.
If the ResourceResolver was looking for a specific version of a
resource and could not find it, this version number is now shown
in the error message.
2016-03-30 11:01:35 +01:00
b1f607ef70 Merge pull request from setrofim/master
trace-cmd fixes
2016-03-24 18:13:16 +00:00
107e8414bb trace-cmd: set a minimum bound on trace pull timeout
The timeout for the pulling the trace file after the run is being set
based on the time for which the trace was collected. For workloads with
short execution time, but large number of events, the resulting timeout
might be too short. To deal with this, do not let the timout be shorter
than 1 minute.
2016-03-24 16:49:42 +00:00
4f8b7e9f59 trace-cmd: updating sched_switch parser to handle both formats.
Depending on the kernel, sched_switch events may be formatted one of two
different ways in the text output. Previously, we've only handled the
"old" format. This commit updates the parser to handle the new format as
well.
2016-03-24 16:33:29 +00:00
a077e7df3c Merge pull request from ep1cman/master
BaseLinuxDevice: gzipped property files are now zcat'ed
2016-03-24 16:30:32 +00:00
a2257fe1e2 BaseLinuxDevice: gzipped property files are now zcat'ed
Before they were cat'ed this gave garbage output for compressed files.
Cat-ing is necessary since not all properties are normal files (sysfs).
2016-03-24 16:28:19 +00:00
50353d0b8f Merge pull request from Sticklyman1936/lmbench_update
lmbench: Tidied up the code and improved stability
2016-03-24 16:26:52 +00:00
0f5621ff66 Merge pull request from Sticklyman1936/sysbench_fix
sysbench: use device busybox binary
2016-03-24 16:24:38 +00:00
2eca77fb02 sysbench: use device busybox binary
Use the full path to busybox on the target device as opposed to
assuming it is found on the path.
2016-03-24 16:21:01 +00:00
3de5b5fe0b lmbench: Tidied up the code and improved stability
This patch tidies up the benchmark code to bring it in line with the
style used in Workload Automation in general. Additionally, the
results from sub-benchmarks are now directly written to a file on the
device as opposed to processing the standard output/error from the
benchmark, which was error prone.
2016-03-24 10:20:32 +00:00
499a9f4082 Merge pull request from setrofim/master
applaunch: pass the location of busybox into the script
2016-03-23 16:32:50 +00:00
3043506d86 applaunch: pass the location of busybox into the script
applaunch creates and deploys an auxilary script in order to collect
precise timings. This script invoked busybox with the assumption that it
is in PATH.

Since recent changes mean that it is no longer deployed to /system/bin,
the busybox in not found. With this commit, the full path to busybox
will be passed into the script's template.
2016-03-23 16:28:18 +00:00
7db904b359 Merge pull request from ep1cman/master
adb_shell: Fixed checking exit codes on Android N
2016-03-23 13:51:17 +00:00
5abeb7aac2 adb_shell: Fixed checking exit codes on Android N
As of android N '\n' is used as the new line separator not '\r\n'.
This fix makes the function detect which is being used by the device.
2016-03-23 13:43:07 +00:00
e04691afb9 Merge pull request from ep1cman/master
daq: Fixed channel merging
2016-03-21 11:22:10 +00:00
15ced50640 daq: Fixed channel merging
Fixed channel merging when setting merge to True.
Channel merges done by setting a mapping manually were not affected by this bug.
2016-03-21 11:15:30 +00:00
1a2e1fdf75 Merge pull request from ep1cman/master
dhyrstone: Fixed arm64 binary
2016-03-15 14:40:47 +00:00
3531dd6d07 dhyrstone: Fixed arm64 binary
It was dynamically linked, its is now statically linked
2016-03-15 14:38:18 +00:00
cf55f317f8 Merge pull request from ep1cman/master
freq_sweep: Improved documentation
2016-03-09 16:52:04 +00:00
79554a2dbc freq_sweep: Improved documentation
- Added explanation that this instrument does not taskset workloads
 - Fixed formatting issue with the agenda example
2016-03-09 16:37:15 +00:00
06c232545a Merge pull request from ep1cman/master
dhrystone: Updated executable resolution
2016-03-09 14:57:49 +00:00
11184750ec dhrystone: Updated executable resolution
Previously it was just using the binary in the dhrystone folder.
Now it uses WA's resource resolution to use the correct ABI.
2016-03-09 14:54:39 +00:00
77b221fc5a Merge pull request from ep1cman/master
daq: Added check for duplicate channel labels
2016-03-08 12:54:33 +00:00
20cd6a9c18 daq: Added check for duplicate channel labels
The daq instrument will no longer accept duplicate channel names.
This caused issues where files sent from the daq sever were being
overwritten.
2016-03-07 13:21:40 +00:00
34d7e7055a Merge pull request from setrofim/master
run command: more usefull error message when specifying non-existing agenda path
2016-02-29 17:28:29 +00:00
0c1e01cad4 run command: more usefull error message when specifying non-existing agenda path
If the specified agenda argument is not found in the file system, WA
assumes it is the name of a workload and would then raise an "extension
not found error", which may be confusing if the user's intension was to
specify a path.

Now, WA will first check that neither path separator, nor a '.' are
present in the agenda argument before assuming it is a workload name, and
will provide a less confusing error in that case.
2016-02-29 17:26:29 +00:00
a68e46eb0a Merge pull request from setrofim/master
LinuxDevice: fixed reboot.
2016-02-22 10:00:51 +00:00
203a3f7d07 LinuxDevice: fixed reboot.
- Deal with the dropped connection on issuing "reboot"
- Introduced a fixed initial delay before polling for connection to
  avoid re-connecting to adevice that is still in the process of
  shutting down.
2016-02-22 09:45:42 +00:00
614 changed files with 26956 additions and 5857 deletions
.gitignoreREADME.rst
dev_scripts
doc
setup.py
wlauto
__init__.pyagenda-example-biglittle.yaml
commands
common
config_example.py
core
devices
__init__.py
android
linux
XE503C12
__init__.py
chromeos_test_image
odroidxu3_linux
external
instrumentation
__init__.py
acmecape
daq
delay
dmesg
energy_model
energy_probe
fps
freqsweep
hwmon
juno_energy
misc
netstats
perf
__init__.py
bin
armeabi
poller
screenon
servo_power_monitors
trace_cmd
modules
resource_getters
result_processors
tests
tools
utils
workloads
__init__.py
adobereader
andebench
androbench
angrybirds
angrybirds_rio
anomaly2
antutu
apklaunch
applaunch
appshare
audio
autotest
bbench
benchmarkpi
blogbench
caffeinemark
cameracapture
camerarecord
castlemaster
cfbench
citadel
cyclictest
dex2oat
dhrystone
facebook
geekbench
glbcorp
glbenchmark
gmail
googlemap
googlephotos
googleplaybooks
googleslides
gunbros2
homescreen
hwuitest
idle
linpack
lmbench
manual
nenamark
octaned8
peacekeeper
power_loadtest
quadrant
real_linpack
realracing3
recentfling
rt_app
skype
skypevideo
smartbench
spec2000
sqlite
stress_ng
sysbench
thechase
vellamo
video
videostreaming
youtube

17
.gitignore vendored

@ -3,6 +3,7 @@
*.bak
*.o
*.cmd
*.iml
Module.symvers
modules.order
*~
@ -14,9 +15,12 @@ wa_output/
doc/source/api/
doc/source/extensions/
MANIFEST
wlauto/external/uiautomator/bin/
wlauto/external/uiautomator/*.properties
wlauto/external/uiautomator/build.xml
wlauto/external/uiauto/**/build/
wlauto/external/uiauto/*.properties
wlauto/external/uiauto/app/libs/
wlauto/external/uiauto/app/proguard-rules.pro
wlauto/external/uiauto/**/.gradle
wlauto/external/uiauto/**/.idea
*.orig
local.properties
wlauto/external/revent/libs/
@ -27,4 +31,9 @@ pmu_logger.mod.c
.tmp_versions
obj/
libs/armeabi
wlauto/workloads/*/uiauto/bin/
wlauto/workloads/*/uiauto/**/build/
wlauto/workloads/*/uiauto/*.properties
wlauto/workloads/*/uiauto/app/libs/
wlauto/workloads/*/uiauto/app/proguard-rules.pro
wlauto/workloads/*/uiauto/**/.gradle
wlauto/workloads/*/uiauto/**/.idea

@ -1,6 +1,19 @@
Workload Automation
+++++++++++++++++++
.. raw:: html
<span style="border: solid red 3px">
<p align="center">
<font color="red">DO NOT USE "MASTER" BRANCH</font>. WA2 has been
deprecated in favor of WA3, which is currently on "next" branch.
</p>
<p align="center">
The master branch will be aligned with next shortly. In the mean time,
please <font style="bold">USE "NEXT" BRANCH</font> instead.
</p>
</span>
Workload Automation (WA) is a framework for executing workloads and collecting
measurements on Android and Linux devices. WA includes automation for nearly 50
workloads (mostly Android), some common instrumentation (ftrace, ARM
@ -46,7 +59,8 @@ documentation.
Documentation
=============
You can view pre-built HTML documentation `here <http://pythonhosted.org/wlauto/>`_.
You can view pre-built HTML documentation
`here <http://workload-automation.readthedocs.io/en/latest/>`_.
Documentation in reStructuredText format may be found under ``doc/source``. To
compile it into cross-linked HTML, make sure you have `Sphinx

@ -6,6 +6,11 @@ distributed as part of WA releases.
Scripts
-------
:check_apk_versions: Compares WA workload versions with the versions listed in APK
if there are any incistency it will highlight these. This
requires all APK files to be present for workloads with
versions.
:clean_install: Performs a clean install of WA from source. This will remove any
existing WA install (regardless of whether it was made from
source or through a tarball with pip).

@ -0,0 +1,66 @@
#!/usr/bin/env python
import os
from distutils.version import StrictVersion
from wlauto.core.extension_loader import ExtensionLoader
from wlauto.common.android.workload import ApkWorkload
from wlauto.utils.android import ApkInfo
el = ExtensionLoader()
class fake_config(object):
def __init__(self, ext_loader):
self.ext_loader = ext_loader
self.get_extension = ext_loader.get_extension
class fake_device(object):
platform = "android"
config = fake_config(el)
device = fake_device()
if "WA_USER_DIRECTORY" in os.environ:
base_path = os.environ["WA_USER_DIRECTORY"]
else:
base_path = "~/.workload_automation/dependencies/"
apk_workloads = [e for e in el.list_workloads()
if issubclass(el.get_extension_class(e.name), ApkWorkload)]
for wl in apk_workloads:
# Get versions from workloads
workload_versions = []
for p in wl.parameters:
if p.name == "version" and p.allowed_values:
workload_versions = p.allowed_values
break
else:
continue
dep_path = os.path.join(os.path.expanduser(base_path), wl.name)
apks = [apk for apk in os.listdir(dep_path) if apk.endswith(".apk")]
# Get versions from APK files
apk_versions = []
for apk in apks:
# skip antutu 3d benchmark apk
if apk == "com.antutu.benchmark.full-1.apk":
continue
apk_versions.append(ApkInfo(os.path.join(dep_path, apk)).version_name)
# Output workload info
print "Workload: {}".format(wl.name)
print "Workload Versions: {}".format(sorted(workload_versions, key=StrictVersion))
print "APK versions: {}".format(sorted(apk_versions, key=StrictVersion))
# Check for bad/missing versions
error = False
for v in apk_versions:
if v not in workload_versions:
msg = "APK version '{}' not present in workload list of versions"
print msg.format(v)
error = True
if not error:
print "OK"

@ -10,22 +10,29 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from wlauto.exceptions import WAError, ToolError
from wlauto.utils.doc import format_simple_table
from wlauto.utils.misc import check_output, get_null, which
def get_aapt_path():
"""Return the full path to aapt tool."""
sdk_path = os.getenv('ANDROID_HOME')
if not sdk_path:
raise ToolError('Please make sure you have Android SDK installed and have ANDROID_HOME set.')
build_tools_directory = os.path.join(sdk_path, 'build-tools')
versions = os.listdir(build_tools_directory)
for version in reversed(sorted(versions)):
aapt_path = os.path.join(build_tools_directory, version, 'aapt')
if os.path.isfile(aapt_path):
logging.debug('Found aapt for version {}'.format(version))
return aapt_path
if sdk_path:
build_tools_directory = os.path.join(sdk_path, 'build-tools')
versions = os.listdir(build_tools_directory)
for version in reversed(sorted(versions)):
aapt_path = os.path.join(build_tools_directory, version, 'aapt')
if os.path.isfile(aapt_path):
logging.debug('Found aapt for version {}'.format(version))
return aapt_path
else:
raise ToolError('aapt not found. Please make sure at least one Android platform is installed.')
else:
raise ToolError('aapt not found. Please make sure at least one Android platform is installed.')
logging.debug("ANDROID_HOME is not set, try to find in $PATH.")
aapt_path = which('aapt')
if aapt_path:
logging.debug('Using aapt from {}'.format(aapt_path))
return aapt_path
raise ToolError('Please make sure you have Android SDK installed and have ANDROID_HOME set.')
def get_apks(path):

@ -7,18 +7,11 @@ SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
SPHINXAPI = sphinx-apidoc
SPHINXAPIOPTS =
WAEXT = ./build_extension_docs.py
WAEXTOPTS = source/extensions ../wlauto ../wlauto/external ../wlauto/tests
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
ALLSPHINXAPIOPTS = -f $(SPHINXAPIOPTS) -o source/api ../wlauto
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
@ -58,52 +51,38 @@ coverage:
@echo
@echo "Build finished. The coverage reports are in $(BUILDDIR)/coverage."
api: ../wlauto
rm -rf source/api/*
$(SPHINXAPI) $(ALLSPHINXAPIOPTS)
waext: ../wlauto
rm -rf source/extensions
mkdir -p source/extensions
$(WAEXT) $(WAEXTOPTS)
sigtab: ../wlauto/core/instrumentation.py source/instrumentation_method_map.template
rm -rf source/instrumentation_method_map.rst
./build_instrumentation_method_map.py source/instrumentation_method_map.rst
html: api waext sigtab
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml: api waext sigtab
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml: api waext sigtab
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle: api waext sigtab
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json: api waext sigtab
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp: api waext sigtab
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp: api waext sigtab
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
@ -112,7 +91,7 @@ qthelp: api waext sigtab
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WorkloadAutomation2.qhc"
devhelp: api
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@ -121,64 +100,64 @@ devhelp: api
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/WorkloadAutomation2"
@echo "# devhelp"
epub: api waext sigtab
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex: api waext sigtab
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf: api waext sigtab
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text: api waext sigtab
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man: api waext sigtab
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo: api waext sigtab
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info: api waext sigtab
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext: api waext sigtab
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes: api waext sigtab
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck: api waext sigtab
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest: api waext sigtab
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

@ -17,6 +17,7 @@
import os
import sys
import shutil
from wlauto import ExtensionLoader
from wlauto.utils.doc import get_rst_from_extension, underline
@ -30,6 +31,9 @@ def generate_extension_documentation(source_dir, outdir, ignore_paths):
loader = ExtensionLoader(keep_going=True)
loader.clear()
loader.update(paths=[source_dir], ignore_paths=ignore_paths)
if os.path.exists(outdir):
shutil.rmtree(outdir)
os.makedirs(outdir)
for ext_type in loader.extension_kinds:
if not ext_type in GENERATE_FOR:
continue

@ -16,7 +16,6 @@
import os
import sys
import string
from copy import copy
from wlauto.core.instrumentation import SIGNAL_MAP, PRIORITY_MAP
from wlauto.utils.doc import format_simple_table
@ -25,7 +24,7 @@ from wlauto.utils.doc import format_simple_table
CONVINIENCE_ALIASES = ['initialize', 'setup', 'start', 'stop', 'process_workload_result',
'update_result', 'teardown', 'finalize']
OUTPUT_TEMPLATE_FILE = os.path.join(os.path.dirname(__file__), 'source', 'instrumentation_method_map.template')
OUTPUT_TEMPLATE_FILE = os.path.join(os.path.dirname(__file__), 'source', 'instrumentation_method_map.template')
def escape_trailing_underscore(value):
@ -37,7 +36,9 @@ def generate_instrumentation_method_map(outfile):
signal_table = format_simple_table([(k, v) for k, v in SIGNAL_MAP.iteritems()],
headers=['method name', 'signal'], align='<<')
priority_table = format_simple_table([(escape_trailing_underscore(k), v) for k, v in PRIORITY_MAP.iteritems()],
headers=['prefix', 'priority'], align='<>')
headers=['prefix', 'priority'], align='<>')
if os.path.isfile(outfile):
os.unlink(outfile)
with open(OUTPUT_TEMPLATE_FILE) as fh:
template = string.Template(fh.read())
with open(outfile, 'w') as wfh:

2
doc/requirements.txt Normal file

@ -0,0 +1,2 @@
nose
sphinx==1.6.5

@ -147,7 +147,7 @@ to 15 million. You can specify this using dhrystone's parameters:
wa show dhrystone
see the :ref:`Invocation` section for details.
see the :ref:`Invocation <invocation>` section for details.
In addition to configuring the workload itself, we can also specify
configuration for the underlying device. This can be done by setting runtime

@ -0,0 +1,57 @@
.. _apk_workload_settings:
APK Workloads
=============
APK resolution
--------------
WA has various resource getters that can be configured to locate APK files but for most people APK files
should be kept in the ``$WA_USER_DIRECTORY/dependencies/SOME_WORKLOAD/`` directory. (by default
``~/.workload_automation/dependencies/SOME_WORKLOAD/``). The ``WA_USER_DIRECTORY`` enviroment variable can be used
to chnage the location of this folder. The APK files need to be put into the corresponding directories
for the workload they belong to. The name of the file can be anything but as explained below may need
to contain certain peices of information.
All ApkWorkloads have parameters that affect the way in which APK files are resolved, ``exact_abi``,
``force_install`` and ``check_apk``. Their exact behaviours are outlined below.
.. confval:: exact_abi
If this setting is enabled WA's resource resolvers will look for the devices ABI with any native
code present in the apk. By default this setting is disabled since most apks will work across all
devices. You may wish to enable this feature when working with devices that support multiple ABI's (like
64-bit devices that can run 32-bit APK files) and are specifically trying to test one or the other.
.. confval:: force_install
If this setting is enabled WA will *always* use the APK file on the host, and re-install it on every
iteration. If there is no APK on the host that is a suitable version and/or ABI for the workload WA
will error when ``force_install`` is enabled.
.. confval:: check_apk
This parameter is used to specify a preference over host or target versions of the app. When set to
``True`` WA will prefer the host side version of the APK. It will check if the host has the APK and
if the host APK meets the version requirements of the workload. If does and the target already has
same version nothing will be done, other wise it will overwrite the targets app with the host version.
If the hosts is missing the APK or it does not meet version requirements WA will fall back to the app
on the target if it has the app and it is of a suitable version. When this parameter is set to
``false`` WA will prefer to use the version already on the target if it meets the workloads version
requirements. If it does not it will fall back to search the host for the correct version. In both modes
if neither the host nor target have a suitable version, WA will error and not run the workload.
Some workloads will also feature the follow parameters which will alter the way their APK files are resolved.
.. confval:: version
This parameter is used to specify which version of uiautomation for the workload is used. In some workloads
e.g. ``geekbench`` multiple versions with drastically different UI's are supported. When a workload uses a
version it is required for the APK file to contain the uiautomation version in the file name. In the case
of antutu the file names could be: ``geekbench_2.apk`` or ``geekbench_3.apk``.
.. confval:: variant_name
Some workloads use variants of APK files, this is usually the case with web browser APK files, these work
in exactly the same way as the version, the variant of the apk

@ -1,6 +1,454 @@
=================================
What's New in Workload Automation
=================================
-------------
Version 2.6.0
-------------
.. note:: Users who are currently using the GitHub master version of WA should
uninstall the existing version before upgrading to avoid potential issues.
Additions:
##########
Workloads
~~~~~~~~~
- ``AdobeReader``: A workload that carries out following typical productivity
tasks. These include opening a file, performing various gestures and
zooms on screen and searching for a predefined set of strings.
- ``octaned8``: A workload to run the binary (non-browser) version of the JS
benchmark Octane.
- ``GooglePlayBooks``: A workload to perform standard productivity tasks with
Google Play Books. This workload performs various tasks, such as searching
for a book title online, browsing through a book, adding and removing notes,
word searching, and querying information about the book.
- ``GooglePhotos``: A workload to perform standard productivity tasks with
Google Photos. Carries out various tasks, such as browsing images,
performing zooms, and post-processing the image.
- ``GoogleSlides``: Carries out various tasks, such as creating a new
presentation, adding text, images, and shapes, as well as basic editing and
playing a slideshow.
- ``Youtube``: The workload plays a video, determined by the ``video_source``
parameter. While the video is playing, some common actions such as video
seeking, pausing playback and navigating the comments section are performed.
- ``Skype``: Replacement for the ``skypevideo`` workload. Logs into Skype
and initiates a voice or video call with a contact.
Framework
~~~~~~~~~
- ``AndroidUxPerfWorkload``: Added a new workload class to encapsulate
functionality common to all uxperf workloads.
- ``UxPerfUiAutomation``: Added class which contains methods specific to
UX performance
testing.
- ``get-assets``: Added new script and command to retrieve external assets
for workloads
Results Processors
~~~~~~~~~~~~~~~~~~~
- ``uxperf``: Parses device logcat for `UX_PERF` markers to produce performance
metrics for workload actions using specified instrumentation.
Other
~~~~~
- ``State Detection``: Added feature to use visual state detection to
verify the state of a workload after setup and run.
Fixes/Improvements:
###################
Documentation
~~~~~~~~~~~~~~
- ``Revent``: Added file structure to the documentation.
- Clarified documentation regarding binary dependencies.
- Updated documentation with ``create`` and ``get-assets`` commands.
Instruments
~~~~~~~~~~~~
- ``sysfs_extractor``: Fixed error when `tar.gz` file already existed on device,
now overwrites.
- ``cpufreq``: Fixed error when `tar.gz` file already existed on device, now
overwrites.
- ``file-poller``:
- Improved csv output.
- Added error checking and reporting.
- Changed ``files`` to be a mandatory parameter.
- ``fps``:
- Added a new parameter to fps instrument to specify the time period between
calls to ``dumpsys SurfaceFlinger --latency`` when collecting frame data.
- Added gfxinfo methods to obtain fps stats. Auto detects and uses appropriate
method via android version of device.
- Fixed issue with regex.
- Now handles empty frames correctly.
- ``energy_model``: Ensures that the ``ui`` runtime parameter is only set for
ChromeOS devices.
- ``ftrace``: Added support to handle traces collected by both WA and devlib.
- ``Perf``: Updated 32bit binary file for little endian devices.
Resource Getters
~~~~~~~~~~~~~~~~
- ``http_getter``: Now used to try and find executables files from a
provided ``remove_assets_url``.
Result Processors
~~~~~~~~~~~~~~~~~
- ``cpu_states``: Fixes using stand-alone script with timeline option.
Workloads
~~~~~~~~~
- ``antutu``: Fixed setting permissions of ``FINE_LOCATION`` on some devices.
- ``bbench`` Fixed handling of missing results.
- ``camerarecord``:
- Added frame stats collection through dumpsys gfxinfo.
- Added possibility to select slow_motion recording mode.
- ``Geekbench``:
- Fixed output file listing causing pull failure.
- Added support for Geekbench 4.
- ``recentfling``:
- Fixed issue when binaries were not uninstalled correctly.
- Scripts are now deployed via ``install()`` to ensure they are executable.
- Fixed handling of when a PID file is deleted before reaching processing
results stage.
- Added parameter to not start any apps before flinging.
- ``rt-app``: Added camera recorder simulation.
- ``sysbench``: Added arm64 binary.
- ``Vellamo``: Fixed capitalization in part of UIAutomation to prevent
potential issues.
- ``Spec2000``: Now uses WA deployed version of busybox.
- ``NetStat``: Updated to support new default logcat format in Android 6.
- ``Dex2oat``: Now uses root if available.
Framework
~~~~~~~~~
- ``adb_shell``:
- Fixed issue when using single quoted command with ``adb_shell``.
- Correctly forward stderror to the caller for newer version of adb.
- ``revent``
- Added ``-S`` argument to "record" command to automatically record a
screen capture after a recording is completed.
- Fixed issue with multiple iterations of a revent workload.
- Added ``-s`` option to executable to allow waiting on stdin.
- Removed timeout in command as ``-s`` is specified.
- Revent recordings can now be parsed and used within WA.
- Fixed issue when some recordings wouldn't be retrieved correctly.
- Timeout is now based on recording duration.
- Added `magic` and file version to revent files. Revent files should now
start with ``REVENT`` followed by the file format version.
- Added support for gamepad recording. This type of recording contains
only the events from a gamepad device (which is automatically
identified).
- A ``mode`` field has been added to the recording format to help
distinguish between the normal and gamepad recording types.
- Added ``-g`` option to ``record`` command to expose the gamepad recording
mode.
- The structure of revent code has undergone a major overhaul to improve
maintainability and robustness.
- More detailed ``info`` command output.
- Updated Makefile to support debug/production builds.
- ``Android API``: Upgraded Android API level from 17 to 18.
- ``uiautomator``: The window hierarchy is now dumped to a file when WA fails
on android devices.
- ``AndroidDevice``:
- Added support for downgrading when installing an APK.
- Added a ``broadcast_media_mounted`` method to force a re-index of the
mediaserver cache for a specified directory.
- Now correctly handles ``None`` output for ``get_pids_of()`` when there are no
running processes with the specified name.
- Renamed the capture method from ``capture_view_hierachy`` to
``capture_ui_hierarchy``.
- Changed the file extension of the capture file to ``.uix``
- Added ``-rf`` to delete_files to be consistent with ``LinuxDevice``.
- ``LinuxDevice``: Now ensures output from both stdout and etderr is propagated in
the event of a DeviceError.
- ``APKWorkload``:
- Now ensure APKs are replaced properly when reinstalling.
- Now checks APK version and ABI when installing.
- Fixed error on some devices when trying to grant permissions that were
already granted.
- Fixed some permissions not being granted.
- Now allows disabling the main activity launch in setup (required for some
apps).
- Added parameter to clear data on reset (default behaviour unchanged).
- Ignores exception for non-fatal permission grant failure.
- Fixed issue of multiple versions of the same workload failing to find their APK.
- Added method to ensure a valid apk version is used within a workload.
- Updated how APK resolution is performed to maximise likelihood of
a workload running.
- When ``check_apk`` is ``True`` will prefer host APK and if no suitable APK
is found, will use target APK if the correct version is present. When ``False``
will prefer target apk if it is a valid version otherwise will fallback to
host APK.
- ``RunConfiguration``: Fixed disabling of instruments in workload specs.
- ``Devices``:
- Added network connectivity check for devices.
- Subclasses can now set ``requires_network`` to ``True`` and network
connectivity check will be performed during ``setup()``.
- ``Workloads``:
- Added network check methods.
- Fixed versions to be backwards compatible.
- Updated workload versions to match APK files.
- Fixed issues with calling super.
- ``Assets``: Added script to retrieve external assets for workloads.
- ``Execution``: Added a ``clean_up`` global config option to delete WA files from
devices.
- ``Runner``: No longer takes a screenshot or dump of UI hierarchy for some errors when
unnecessary, e.g. host errors.
- ``core``: Constraints and allowed values are now checked when set instead of
when validating.
- ``FpsProcessor``:
- Added requirement on ``filtered_vsyncs_to_compose`` for ``total_vsync metric``.
- Removed misleading comment in class description.
- ``BaseUiAutomation``: Added new Marker API so workloads generate start and end
markers with a string name.
- ``AndroidUiAutoBenchmark``: Automatically checks for known package versions
that don't work well with AndroidUiAutoBenchmark workloads.
Other
~~~~~
- Updated setup.py url to be a valid URI.
- Fixed workload name in big.Little sample agenda.
Incompatible changes
####################
Framework
~~~~~~~~~
- ``check_abi``: Now renamed to ``exact_abi``, is used to ensure that if enabled,
only an apk containing no native code or code designed for the devices primary
abi is use.
- ``AndroidDevice``: Renamed ``supported_eabis`` property to ``supported_abis``
to be consistent with linux devices.
Workloads
~~~~~~~~~~
- ``skypevideo``: Workload removed and replaced with ``skype`` workload.
-------------
Version 2.5.0
-------------
Additions:
##########
Instruments
~~~~~~~~~~~
- ``servo_power``: Added support for chromebook servo boards.
- ``file_poller``: polls files and outputs a CSV of their values over time.
- ``systrace``: The Systrace tool helps analyze the performance of your
application by capturing and displaying execution times of your applications
processes and other Android system processes.
Workloads
~~~~~~~~~
- ``blogbench``: Blogbench is a portable filesystem benchmark that tries to
reproduce the load of a real-world busy file server.
- ``stress-ng``: Designed to exercise various physical subsystems of a computer
as well as the various operating system kernel interfaces.
- ``hwuitest``: Uses hwuitest from AOSP to test rendering latency on Android
devices.
- ``recentfling``: Tests UI jank on android devices.
- ``apklaunch``: installs and runs an arbitrary apk file.
- ``googlemap``: Launches Google Maps and replays previously recorded
interactions.
Framework
~~~~~~~~~
- ``wlauto.utils.misc``: Added ``memoised`` function decorator that allows
caching of previous function/method call results.
- Added new ``Device`` APIs:
- ``lsmod``: lists kernel modules
- ``insmod``: inserts a kernel module from a ``.ko`` file on the host.
- ``get_binary_path``: Checks ``binary_directory`` for the wanted binary,
if it is not found there it will try to use ``which``
- ``install_if_needed``: Will only install a binary if it is not already
on the target.
- ``get_device_model``: Gets the model of the device.
- ``wlauto.core.execution.ExecutionContext``:
- ``add_classfiers``: Allows adding a classfier to all metrics for the
current result.
Other
~~~~~
- Commands:
- ``record``: Simplifies recording revent files.
- ``replay``: Plays back revent files.
Fixes/Improvements:
###################
Devices
~~~~~~~
- ``juno``:
- Fixed ``bootargs`` parameter not being passed to ``_boot_via_uboot``.
- Removed default ``bootargs``
- ``gem5_linux``:
- Added ``login_prompt`` and ``login_password_prompt`` parameters.
- ``generic_linux``: ABI is now read from the target device.
Instruments
~~~~~~~~~~~
- ``trace-cmd``:
- Added the ability to report the binary trace on the target device,
removing the need for ``trace-cmd`` binary to be present on the host.
- Updated to handle messages that the trace for a CPU is empty.
- Made timeout for pulling trace 1 minute at minimum.
- ``perf``: per-cpu statistics now get added as metrics to the results (with a
classifier used to identify the cpu).
- ``daq``:
- Fixed bug where an exception would be raised if ``merge_channels=False``
- No longer allows duplicate channel labels
- ``juno_energy``:
- Summary metrics are now calculated from the contents of ``energy.csv`` and
added to the overall results.
- Added a ``strict`` parameter. When this is set to ``False`` the device
check during validation is omitted.
- ``sysfs_extractor``: tar and gzip are now performed separately to solve
permission issues.
- ``fps``:
- Now only checks for crashed content if ``crash_check`` is ``True``.
- Can now process multiple ``view`` attributes.
- ``hwmon``: Sensor naming fixed, they are also now added as result classifiers
Resource Getters
~~~~~~~~~~~~~~~~
- ``extension_asset``: Now picks up the path to the mounted filer from the
``remote_assets_path`` global setting.
Result Processors
~~~~~~~~~~~~~~~~~
- ``cpustates``:
- Added the ability to configure how a missing ``START`` marker in the trace
is handled.
- Now raises a warning when there is a ``START`` marker in the trace but no
``STOP`` marker.
- Exceptions in PowerStateProcessor no longer stop the processing of the
rest of the trace.
- Now ensures a known initial state by nudging each CPU to bring it out of
idle and writing starting CPU frequencies to the trace.
- Added the ability to create a CPU utilisation timeline.
- Fixed issues with getting frequencies of hotplugged CPUs
- ``csv``: Zero-value classifieres are no longer converted to an empty entry.
- ``ipynb_exporter``: Default template no longer shows a blank plot for
workloads without ``summary_metrics``
Workloads
~~~~~~~~~
- ``vellamo``:
- Added support for v3.2.4.
- Fixed getting values from logcat.
- ``cameracapture``: Updated to work with Android M+.
- ``camerarecord``: Updated to work with Android M+.
- ``lmbench``:
- Added the output file as an artifact.
- Added taskset support
- ``antutu`` - Added support for v6.0.1
- ``ebizzy``: Fixed use of ``os.path`` to ``self.device.path``.
- ``bbench``: Fixed browser crashes & permissions issues on android M+.
- ``geekbench``:
- Added check whether device is rooted.
- ``manual``: Now only uses logcat on Android devices.
- ``applaunch``:
- Fixed ``cleanup`` not getting forwarded to script.
- Added the ability to stress IO during app launch.
- ``dhrystone``: Now uses WA's resource resolution to find it's binary so it
uses the correct ABI.
- ``glbench``: Updated for new logcat formatting.
Framework
~~~~~~~~~
- ``ReventWorkload``:
- Now kills all revent instances on teardown.
- Device model name is now used when searching for revent files, falling back
to WA device name.
- ``BaseLinuxDevice``:
- ``killall`` will now run as root by default if the device
is rooted.
- ``list_file_systems`` now handles blank lines.
- All binaries are now installed into ``binaries_directory`` this allows..
- Busybox is now deployed on non-root devices.
- gzipped property files are no zcat'ed
- ``LinuxDevice``:
- ``kick_off`` no longer requires root.
- ``kick_off`` will now run as root by default if the device is rooted.
- No longer raises an exception if a connection was dropped during a reboot.
- Added a delay before polling for a connection to avoid re-connecting to a
device that is still in the process of rebooting.
- ``wlauto.utils.types``: ``list_or_string`` now ensures that elements of a list
are strings.
- ``AndroidDevice``:
- ``kick_off`` no longer requires root.
- Build props are now gathered via ``getprop`` rather than trying to parse
build.prop directly.
- WA now pushes its own ``sqlite3`` binary.
- Now uses ``content`` instead of ``settings`` to get ``ANDROID_ID``
- ``swipe_to_unlock`` parameter is now actually used. It has been changed to
take a direction to accomodate various devices.
- ``ensure_screen_is_on`` will now also unlock the screen if swipe_to_unlock
is set.
- Fixed use of variables in as_root=True commands.
- ``get_pids_of`` now used ``busybox grep`` since as of Android M+ ps cannot
filter by process name anymore.
- Fixed installing APK files with whitespace in their path/name.
- ``adb_shell``:
- Fixed handling of line breaks at the end of command output.
- Newline separator is now detected from the target.
- As of ADB v1.0.35, ADB returns the return code of the command run. WA now
handles this correctly.
- ``ApkWorkload``:
- Now attempts to grant all runtime permissions for devices on Android M+.
- Can now launch packages that don't have a launch activity defined.
- Package version is now added to results as a classifier.
- Now clears app data if an uninstall failed to ensure it starts from a known
state.
- ``wlauto.utils.ipython``: Updated to work with ipython v5.
- ``Gem5Device``:
- Added support for deploying the ``m5`` binary.
- No longer waits for the boot animation to finish if it has been disabled.
- Fixed runtime error caused by lack of kwargs.
- No longer depends on ``busybox``.
- Split out commands to resize shell to ``resize_shell``.
- Now tries to connect to the shell up to 10 times.
- No longer renames gzipped files.
- Agendas:
- Now errors when an agenda key is empty.
- ``wlauto.core.execution.RunInfo``: ``run_name`` will now default to
``{output_folder}_{date}_{time}``.
- Extensions:
- Two different parameters can now have the same global alias as long as they
their types match.
- You can no longer ``override`` parameters that are defined at the same
level.
- ``wlauto.core.entry_point``: Now gives a better error when a config file
doesn't exist.
- ``wlauto.utils.misc``: Added ``aarch64`` to list for arm64 ABI.
- ``wlauto.core.resolver``: Now shows what version was being search for when a
resource is not found.
- Will no longer start instruments ect. if a run has no workload specs.
- ``wlauto.utils.uboot``: Now detects uboot version to use correct line endings.
- ``wlauto.utils.trace_cmd``: Added a parser for sched_switch events.
Other
~~~~~
- Updated to pylint v1.5.1
- Rebuilt ``busybox`` binaries to prefer built-in applets over system binaries.
- ``BaseUiAutomation``: Added functions for checking version strings.
Incompatible changes
####################
Instruments
~~~~~~~~~~~
- ``apk_version``: Removed, use result classifiers instead.
Framework
~~~~~~~~~
- ``BaseLinuxDevice``: Removed ``is_installed`` use ``install_if_needed`` and
``get_binary_path`` instead.
- ``LinuxDevice``: Removed ``has_root`` method, use ``is_rooted`` instead.
- ``AndroidDevice``: ``swipe_to_unlock`` method replaced with
``perform_unlock_swipe``.
-------------
Version 2.4.0
-------------

@ -28,12 +28,16 @@
import sys, os
import warnings
from sphinx.apidoc import main
warnings.filterwarnings('ignore', "Module louie was already imported")
this_dir = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(this_dir, '..'))
sys.path.insert(0, os.path.join(this_dir, '../..'))
import wlauto
from build_extension_docs import generate_extension_documentation
from build_instrumentation_method_map import generate_instrumentation_method_map
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@ -264,7 +268,21 @@ texinfo_documents = [
#texinfo_show_urls = 'footnote'
def run_apidoc(_):
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
cur_dir = os.path.abspath(os.path.dirname(__file__))
api_output = os.path.join(cur_dir, 'api')
module = os.path.join(cur_dir, '..', '..', 'wlauto')
main(['-f', '-o', api_output, module, '--force'])
def setup(app):
module_dir = os.path.join('..', '..', 'wlauto')
excluded_extensions = [os.path.join(module_dir, 'external'),
os.path.join(module_dir, 'tests')]
os.chdir(os.path.dirname(__file__))
app.connect('builder-inited', run_apidoc)
generate_instrumentation_method_map('instrumentation_method_map.rst')
generate_extension_documentation(module_dir, 'extensions', excluded_extensions)
app.add_object_type('confval', 'confval',
objname='configuration value',
indextemplate='pair: %s; configuration value')

@ -118,6 +118,7 @@ and detailed descriptions of how WA functions under the hood.
additional_topics
daq_device_setup
revent
apk_workloads
contributing
API Reference

@ -59,6 +59,11 @@ usually the best bet.
Optionally (but recommended), you should also set ``ANDROID_HOME`` to point to
the install location of the SDK (i.e. ``<path_to_android_sdk>/sdk``).
.. note:: You may need to install 32-bit compatibility libararies for the SDK
to work properly. On Ubuntu you need to run::
sudo apt-get install lib32stdc++6 lib32z1
Python
------
@ -87,7 +92,7 @@ similar distributions, this may be done with APT::
If you do run into this issue after already installing some packages,
you can resolve it by running ::
sudo chmod -R a+r /usr/local/lib/python2.7/dist-packagessudo
sudo chmod -R a+r /usr/local/lib/python2.7/dist-packagessudo
find /usr/local/lib/python2.7/dist-packages -type d -exec chmod a+x {} \;
(The paths above will work for Ubuntu; they may need to be adjusted
@ -187,10 +192,28 @@ version $version".
Some WA extensions have additional dependencies that need to be
statisfied before they can be used. Not all of these can be provided with WA and
so will need to be supplied by the user. They should be placed into
``~/.workload_uatomation/dependencies/<extenion name>`` so that WA can find
``~/.workload_automation/dependencies/<extenion name>`` so that WA can find
them (you may need to create the directory if it doesn't already exist). You
only need to provide the dependencies for workloads you want to use.
Binary Files
------------
Some workloads require native binaries to work. Different binaries will be required
for different ABIs. WA may not include the required binary for a workload due to
licensing/distribution issues, or may not have a binary compiled for your device's
ABI. In such cases, you will have to supply the missing binaries.
Executable binaries for a workload should be placed inside
``~/.workload_automation/dependencies/<extension name>/bin/<ABI>`` directory.
This directory may not already exist, in which case you would have to create it.
Binaries placed in that location will take precidence over any already inclueded with
WA. For example, if you have your own ``drystone`` binary compiled for ``arm64``,
and you want WA to pick it up, you can do the following on WA host machine ::
mkdir -p ~/.workload_automation/dependencies/dhrystone/bin/arm64/
cp /path/to/your/dhrystone ~/.workload_automation/dependencies/dhrystone/bin/arm64/
APK Files
---------
@ -307,7 +330,7 @@ that location.
If you have installed Workload Automation via ``pip`` and wish to remove it, run this command to
uninstall it::
sudo -H pip uninstall wlauto
.. Note:: This will *not* remove any user configuration (e.g. the ~/.workload_automation directory)
@ -317,5 +340,5 @@ uninstall it::
====================
To upgrade Workload Automation to the latest version via ``pip``, run::
sudo -H pip install --upgrade --no-deps wlauto

@ -1,11 +1,12 @@
.. _invocation:
.. highlight:: none
========
Commands
========
Installing the wlauto package will add ``wa`` command to your system,
which you can run from anywhere. This has a number of sub-commands, which can
which you can run from anywhere. This has a number of sub-commands, which can
be viewed by executing ::
wa -h
@ -15,7 +16,7 @@ Individual sub-commands are discussed in detail below.
run
---
The most common sub-command you will use is ``run``. This will run specfied
The most common sub-command you will use is ``run``. This will run specified
workload(s) and process resulting output. This takes a single mandatory
argument that specifies what you want WA to run. This could be either a
workload name, or a path to an "agenda" file that allows to specify multiple
@ -24,7 +25,7 @@ section for details). Executing ::
wa run -h
Will display help for this subcommand that will look somehtign like this::
Will display help for this subcommand that will look something like this::
usage: run [-d DIR] [-f] AGENDA
@ -47,13 +48,13 @@ Will display help for this subcommand that will look somehtign like this::
--debug Enable debug mode. Note: this implies --verbose.
-d DIR, --output-directory DIR
Specify a directory where the output will be
generated. If the directoryalready exists, the script
generated. If the directory already exists, the script
will abort unless -f option (see below) is used,in
which case the contents of the directory will be
overwritten. If this optionis not specified, then
overwritten. If this option is not specified, then
wa_output will be used instead.
-f, --force Overwrite output directory if it exists. By default,
the script will abort in thissituation to prevent
the script will abort in this situation to prevent
accidental data loss.
-i ID, --id ID Specify a workload spec ID from an agenda to run. If
this is specified, only that particular spec will be
@ -81,10 +82,74 @@ agenda file used to run the workloads along with any other device-specific
configuration files used during execution.
create
------
This can be used to create various WA-related objects, currently workloads, packages and agendas.
The full set of options for this command are::
usage: wa create [-h] [-c CONFIG] [-v] [--debug] [--version]
{workload,package,agenda} ...
positional arguments:
{workload,package,agenda}
workload Create a new workload. By default, a basic workload
template will be used but you can use options to
specify a different template.
package Create a new empty Python package for WA extensions.
On installation, this package will "advertise" itself
to WA so that Extensions with in it will be loaded by
WA when it runs.
agenda Create an agenda whit the specified extensions
enabled. And parameters set to their default values.
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
Use "wa create <object> -h" to see all the object-specific arguments. For example::
wa create agenda -h
will display the relevant options that can be used to create an agenda.
get-assets
----------
This command can download external extension dependencies used by Workload Automation.
It can be used to download assets for all available extensions or those specificity listed.
The full set of options for this command are::
usage: wa get-assets [-h] [-c CONFIG] [-v] [--debug] [--version] [-f]
[--url URL] (-a | -e EXT [EXT ...])
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
-f, --force Always fetch the assets, even if matching versions
exist in local cache.
--url URL The location from which to download the files. If not
provided, config setting ``remote_assets_url`` will be
used if available, else uses the default
REMOTE_ASSETS_URL parameter in the script.
-a, --all Download assets for all extensions found in the index.
Cannot be used with -e.
-e EXT [EXT ...] One or more extensions whose assets to download.
Cannot be used with --all.
list
----
This lists all extensions of a particular type. For example ::
This lists all extensions of a particular type. For example::
wa list workloads
@ -97,11 +162,11 @@ show
This will show detailed information about an extension, including more in-depth
description and any parameters/configuration that are available. For example
executing ::
executing::
wa show andebench
will produce something like ::
will produce something like::
andebench
@ -131,5 +196,64 @@ will produce something like ::
- Results displayed in Iterations per second
- Detailed log file for comprehensive engineering analysis
.. _record-command:
record
------
This command simplifies the process of recording an revent file. It
will automatically deploy revent and even has the option of automatically
opening apps. WA uses two parts to the names of revent recordings in the
format, {device_name}.{suffix}.revent. - device_name can either be specified
manually with the ``-d`` argument or it can be automatically determined. On
Android device it will be obtained from ``build.prop``, on Linux devices it is
obtained from ``/proc/device-tree/model``. - suffix is used by WA to determine
which part of the app execution the recording is for, currently these are
either ``setup`` or ``run``. This should be specified with the ``-s``
argument. The full set of options for this command are::
usage: wa record [-h] [-c CONFIG] [-v] [--debug] [--version] [-d DEVICE]
[-s SUFFIX] [-o OUTPUT] [-p PACKAGE] [-g] [-C]
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
-d DEVICE, --device DEVICE
The name of the device
-s SUFFIX, --suffix SUFFIX
The suffix of the revent file, e.g. ``setup``
-o OUTPUT, --output OUTPUT
Directory to save the recording in
-p PACKAGE, --package PACKAGE
Package to launch before recording
-g, --gamepad Record from a gamepad rather than all devices.
-C, --clear Clear app cache before launching it
.. _replay-command:
replay
------
Along side ``record`` wa also has a command to playback recorded revent files.
It behaves very similar to the ``record`` command taking many of the same options::
usage: wa replay [-h] [-c CONFIG] [-v] [--debug] [--version] [-p PACKAGE] [-C]
revent
positional arguments:
revent The name of the file to replay
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
specify an additional config.py
-v, --verbose The scripts will produce verbose output.
--debug Enable debug mode. Note: this implies --verbose.
--version show program's version number and exit
-p PACKAGE, --package PACKAGE
Package to launch before recording
-C, --clear Clear app cache before launching it

@ -1,7 +1,10 @@
.. _revent_files_creation:
revent
======
++++++
Overview and Usage
==================
revent utility can be used to record and later play back a sequence of user
input events, such as key presses and touch screen taps. This is an alternative
@ -17,36 +20,47 @@ to Android UI Automator for providing automation for workloads. ::
info:shows info about each event char device
any additional parameters make it verbose
.. note:: There are now also WA commands that perform the below steps.
Please see ``wa show record/replay`` and ``wa record/replay --help``
for details.
Recording
---------
To record, transfer the revent binary to the device, then invoke ``revent
record``, giving it the time (in seconds) you want to record for, and the
file you want to record to (WA expects these files to have .revent
extension)::
WA features a ``record`` command that will automatically deploy and start
revent on the target device::
host$ adb push revent /data/local/revent
host$ adb shell
device# cd /data/local
device# ./revent record 1000 my_recording.revent
wa record
INFO Connecting to device...
INFO Press Enter when you are ready to record...
[Pressed Enter]
INFO Press Enter when you have finished recording...
[Pressed Enter]
INFO Pulling files from device
Once started, you will need to get the target device ready to record (e.g.
unlock screen, navigate menus and launch an app) then press ``ENTER``.
The recording has now started and button presses, taps, etc you perform on
the device will go into the .revent file. To stop the recording simply press
``ENTER`` again.
Once you have finished recording the revent file will be pulled from the device
to the current directory. It will be named ``{device_model}.revent``. When
recording revent files for a ``GameWorkload`` you can use the ``-s`` option to
add ``run`` or ``setup`` suffixes.
From version 2.6 of WA onwards, a "gamepad" recording mode is also supported.
This mode requires a gamepad to be connected to the device when recoridng, but
the recordings produced in this mode should be portable across devices.
For more information run please read :ref:`record-command`
The recording has now started and button presses, taps, etc you perform on the
device will go into the .revent file. The recording will stop after the
specified time period, and you can also stop it by hitting return in the adb
shell.
Replaying
---------
To replay a recorded file, run ``revent replay`` on the device, giving it the
file you want to replay::
To replay a recorded file, run ``wa replay``, giving it the file you want to
replay::
device# ./revent replay my_recording.revent
wa replay my_recording.revent
For more information run please read :ref:`replay-command`
Using revent With Workloads
@ -100,3 +114,359 @@ where as UI Automator only works for Android UI elements (such as text boxes or
radio buttons), which makes the latter useless for things like games. Recording
revent sequence is also faster than writing automation code (on the other hand,
one would need maintain a different revent log for each screen resolution).
Using state detection with revent
=================================
State detection can be used to verify that a workload is executing as expected.
This utility, if enabled, and if state definitions are available for the
particular workload, takes a screenshot after the setup and the run revent
sequence, matches the screenshot to a state and compares with the expected
state. A WorkloadError is raised if an unexpected state is encountered.
To enable state detection, make sure a valid state definition file and
templates exist for your workload and set the check_states parameter to True.
State definition directory
--------------------------
State and phase definitions should be placed in a directory of the following
structure inside the dependencies directory of each workload (along with
revent files etc):
::
dependencies/
<workload_name>/
state_definitions/
definition.yaml
templates/
<oneTemplate>.png
<anotherTemplate>.png
...
definition.yaml file
--------------------
This defines each state of the workload and lists which templates are expected
to be found and how many are required to be detected for a conclusive match. It
also defines the expected state in each workload phase where a state detection
is run (currently those are setup_complete and run_complete).
Templates are picture elements to be matched in a screenshot. Each template
mentioned in the definition file should be placed as a file with the same name
and a .png extension inside the templates folder. Creating template png files
is as simple as taking a screenshot of the workload in a given state, cropping
out the relevant templates (eg. a button, label or other unique element that is
present in that state) and storing them in PNG format.
Please see the definition file for Angry Birds below as an example to
understand the format. Note that more than just two states (for the afterSetup
and afterRun phase) can be defined and this helps track the cause of errors in
case an unexpected state is encountered.
.. code-block:: yaml
workload_name: angrybirds
workload_states:
- state_name: titleScreen
templates:
- play_button
- logo
matches: 2
- state_name: worldSelection
templates:
- first_world_thumb
- second_world_thumb
- third_world_thumb
- fourth_world_thumb
matches: 3
- state_name: level_selection
templates:
- locked_level
- first_level
matches: 2
- state_name: gameplay
templates:
- pause_button
- score_label_text
matches: 2
- state_name: pause_screen
templates:
- replay_button
- menu_button
- resume_button
- help_button
matches: 4
- state_name: level_cleared_screen
templates:
- level_cleared_text
- menu_button
- replay_button
- fast_forward_button
matches: 4
workload_phases:
- phase_name: setup_complete
expected_state: gameplay
- phase_name: run_complete
expected_state: level_cleared_screen
File format of revent recordings
================================
You do not need to understand recording format in order to use revent. This
section is intended for those looking to extend revent in some way, or to
utilize revent recordings for other purposes.
Format Overview
---------------
Recordings are stored in a binary format. A recording consists of three
sections::
+-+-+-+-+-+-+-+-+-+-+-+
| Header |
+-+-+-+-+-+-+-+-+-+-+-+
| |
| Device Description |
| |
+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| Event Stream |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+
The header contains metadata describing the recording. The device description
contains information about input devices involved in this recording. Finally,
the event stream contains the recorded input events.
All fields are either fixed size or prefixed with their length or the number of
(fixed-sized) elements.
.. note:: All values below are little endian
Recording Header
----------------
An revent recoding header has the following structure
* It starts with the "magic" string ``REVENT`` to indicate that this is an
revent recording.
* The magic is followed by a 16 bit version number. This indicates the format
version of the recording that follows. Current version is ``2``.
* The next 16 bits indicate the type of the recording. This dictates the
structure of the Device Description section. Valid values are:
``0``
This is a general input event recording. The device description
contains a list of paths from which the events where recorded.
``1``
This a gamepad recording. The device description contains the
description of the gamepad used to create the recording.
* The header is zero-padded to 128 bits.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 'R' | 'E' | 'V' | 'E' |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 'N' | 'T' | Version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Mode | PADDING |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PADDING |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Device Description
------------------
This section describes the input devices used in the recording. Its structure is
determined by the value of ``Mode`` field in the header.
general recording
~~~~~~~~~~~~~~~~~
.. note:: This is the only format supported prior to version ``2``.
The recording has been made from all available input devices. This section
contains the list of ``/dev/input`` paths for the devices, prefixed with total
number of the devices recorded.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number of devices |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Device paths +-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Similarly, each device path is a length-prefixed string. Unlike C strings, the
path is *not* NULL-terminated.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length of device path |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Device path |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
gamepad recording
~~~~~~~~~~~~~~~~~
The recording has been made from a specific gamepad. All events in the stream
will be for that device only. The section describes the device properties that
will be used to create a virtual input device using ``/dev/uinput``. Please
see ``linux/input.h`` header in the Linux kernel source for more information
about the fields in this section.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| bustype | vendor |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| product | version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name_length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| name |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ev_bits |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| key_bits (96 bytes) |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| rel_bits (96 bytes) |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| abs_bits (96 bytes) |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| num_absinfo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| |
| |
| |
| absinfo entries |
| |
| |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Each ``absinfo`` entry consists of six 32 bit values. The number of entries is
determined by the ``abs_bits`` field.
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| value |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| minimum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| maximum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| fuzz |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| flat |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| resolution |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Event structure
---------------
The majority of an revent recording will be made up of the input events that were
recorded. The event stream is prefixed with the number of events in the stream.
Each event entry structured as follows:
* An unsigned integer representing which device from the list of device paths
this event is for (zero indexed). E.g. Device ID = 3 would be the 4th
device in the list of device paths.
* A signed integer representing the number of seconds since "epoch" when the
event was recorded.
* A signed integer representing the microseconds part of the timestamp.
* An unsigned integer representing the event type
* An unsigned integer representing the event code
* An unsigned integer representing the event value
For more information about the event type, code and value please read:
https://www.kernel.org/doc/Documentation/input/event-codes.txt
::
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Device ID | Timestamp Seconds |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Seconds (cont.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Seconds (cont.) | stamp Micoseconds |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Micoseconds (cont.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp Micoseconds (cont.) | Event Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Event Code | Event Value |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Event Value (cont.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Parser
------
WA has a parser for revent recordings. This can be used to work with revent
recordings in scripts. Here is an example:
.. code:: python
from wlauto.utils.revent import ReventRecording
with ReventRecording('/path/to/recording.revent') as recording:
print "Recording: {}".format(recording.filepath)
print "There are {} input events".format(recording.num_events)
print "Over a total of {} seconds".format(recording.duration)

@ -161,8 +161,8 @@ In order for the binary to be obtained in this way, it must be stored in one of
the locations scanned by the resource resolver in a directry structure
``<root>/bin/<abi>/<binary>`` (where ``root`` is the base resource location to
be searched, e.g. ``~/.workload_automation/depencencies/<extension name>``, and
``<abi>`` is the ABI for which the exectuable has been compiled, as returned by
``self.device.abi``).
``<abi>`` is the ABI for which the exectuable has been compiled, as returned by
``self.device.abi``).
Once the path to the host-side binary has been obtained, it may be deployed using
one of two methods of a ``Device`` instace -- ``install`` or ``install_if_needed``.
@ -182,8 +182,8 @@ WA and will not try to re-install.
Both of the above methods will return the path to the installed binary on the
device. The executable should be invoked *only* via that path; do **not** assume
that it will be in ``PATH`` on the target (or that the executable with the same
name in ``PATH`` is the version deployed by WA.
that it will be in ``PATH`` on the target (or that the executable with the same
name in ``PATH`` is the version deployed by WA.
.. code:: python
@ -964,7 +964,7 @@ that accompanies them, in addition to what has been outlined here, should
provide enough guidance.
:commands: This allows extending WA with additional sub-commands (to supplement
exiting ones outlined in the :ref:`invocation` section).
exiting ones outlined in the :ref:`invocation <invocation>` section).
:modules: Modules are "extensions for extensions". They can be loaded by other
extensions to expand their functionality (for example, a flashing
module maybe loaded by a device in order to support flashing).

@ -66,7 +66,7 @@ params = dict(
packages=packages,
package_data=data_files,
scripts=scripts,
url='N/A',
url='http://github.com/arm-sowftware/workload-automation',
license='Apache v2',
maintainer='ARM Architecture & Technology Device Lab',
maintainer_email='workload-automation@arm.com',
@ -80,6 +80,7 @@ params = dict(
],
extras_require={
'other': ['jinja2', 'pandas>=0.13.1'],
'statedetect': ['numpy', 'imutils', 'opencv-python'],
'test': ['nose'],
'mongodb': ['pymongo'],
'notify': ['notify2'],

@ -29,7 +29,7 @@ from wlauto.common.linux.device import LinuxDevice # NOQA
from wlauto.common.android.device import AndroidDevice, BigLittleDevice # NOQA
from wlauto.common.android.resources import ApkFile, JarFile
from wlauto.common.android.workload import (UiAutomatorWorkload, ApkWorkload, AndroidBenchmark, # NOQA
AndroidUiAutoBenchmark, GameWorkload) # NOQA
AndroidUiAutoBenchmark, AndroidUxPerfWorkload, GameWorkload) # NOQA
from wlauto.core.version import get_wa_version

@ -1,6 +1,6 @@
# This agenda specifies configuration that may be used for regression runs
# on big.LITTLE systems. This agenda will with a TC2 device configured as
# described in the documentation.
# on big.LITTLE systems. This agenda will work with a TC2 device configured
# as described in the documentation.
config:
device: tc2
run_name: big.LITTLE_regression
@ -69,7 +69,7 @@ workloads:
- id: b10
name: smartbench
- id: b11
name: sqlite
name: sqlitebm
- id: b12
name: vellamo

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -22,7 +22,6 @@ import textwrap
import argparse
import shutil
import getpass
import subprocess
from collections import OrderedDict
import yaml
@ -30,8 +29,9 @@ import yaml
from wlauto import ExtensionLoader, Command, settings
from wlauto.exceptions import CommandError, ConfigError
from wlauto.utils.cli import init_argument_parser
from wlauto.utils.misc import (capitalize, check_output,
ensure_file_directory_exists as _f, ensure_directory_exists as _d)
from wlauto.utils.misc import (capitalize,
ensure_file_directory_exists as _f,
ensure_directory_exists as _d)
from wlauto.utils.types import identifier
from wlauto.utils.doc import format_body
@ -41,20 +41,6 @@ __all__ = ['create_workload']
TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), 'templates')
UIAUTO_BUILD_SCRIPT = """#!/bin/bash
class_dir=bin/classes/com/arm/wlauto/uiauto
base_class=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', 'BaseUiAutomation.class')"`
mkdir -p $$class_dir
cp $$base_class $$class_dir
ant build
if [[ -f bin/${package_name}.jar ]]; then
cp bin/${package_name}.jar ..
fi
"""
class CreateSubcommand(object):
@ -321,7 +307,7 @@ def create_basic_workload(path, name, class_name):
def create_uiautomator_workload(path, name, class_name):
uiauto_path = _d(os.path.join(path, 'uiauto'))
uiauto_path = os.path.join(path, 'uiauto')
create_uiauto_project(uiauto_path, name)
source_file = os.path.join(path, '__init__.py')
with open(source_file, 'w') as wfh:
@ -335,37 +321,34 @@ def create_android_benchmark(path, name, class_name):
def create_android_uiauto_benchmark(path, name, class_name):
uiauto_path = _d(os.path.join(path, 'uiauto'))
uiauto_path = os.path.join(path, 'uiauto')
create_uiauto_project(uiauto_path, name)
source_file = os.path.join(path, '__init__.py')
with open(source_file, 'w') as wfh:
wfh.write(render_template('android_uiauto_benchmark', {'name': name, 'class_name': class_name}))
def create_uiauto_project(path, name, target='1'):
sdk_path = get_sdk_path()
android_path = os.path.join(sdk_path, 'tools', 'android')
def create_uiauto_project(path, name):
package_name = 'com.arm.wlauto.uiauto.' + name.lower()
# ${ANDROID_HOME}/tools/android create uitest-project -n com.arm.wlauto.uiauto.linpack -t 1 -p ../test2
command = '{} create uitest-project --name {} --target {} --path {}'.format(android_path,
package_name,
target,
path)
try:
check_output(command, shell=True)
except subprocess.CalledProcessError as e:
if 'is is not valid' in e.output:
message = 'No Android SDK target found; have you run "{} update sdk" and download a platform?'
raise CommandError(message.format(android_path))
shutil.copytree(os.path.join(TEMPLATES_DIR, 'uiauto_template'), path)
manifest_path = os.path.join(path, 'app', 'src', 'main')
mainifest = os.path.join(_d(manifest_path), 'AndroidManifest.xml')
with open(mainifest, 'w') as wfh:
wfh.write(render_template('uiauto_AndroidManifest.xml', {'package_name': package_name}))
build_gradle_path = os.path.join(path, 'app')
build_gradle = os.path.join(_d(build_gradle_path), 'build.gradle')
with open(build_gradle, 'w') as wfh:
wfh.write(render_template('uiauto_build.gradle', {'package_name': package_name}))
build_script = os.path.join(path, 'build.sh')
with open(build_script, 'w') as wfh:
template = string.Template(UIAUTO_BUILD_SCRIPT)
wfh.write(template.substitute({'package_name': package_name}))
wfh.write(render_template('uiauto_build_script', {'package_name': package_name}))
os.chmod(build_script, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
source_file = _f(os.path.join(path, 'src',
source_file = _f(os.path.join(path, 'app', 'src', 'main', 'java',
os.sep.join(package_name.split('.')[:-1]),
'UiAutomation.java'))
with open(source_file, 'w') as wfh:

@ -0,0 +1,122 @@
# Copyright 2014-2015 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.
#
import sys
import argparse
from requests import ConnectionError, RequestException
from wlauto import File, ExtensionLoader, Command, settings
from wlauto.core.extension import Extension
REMOTE_ASSETS_URL = 'https://github.com/ARM-software/workload-automation-assets/raw/master/dependencies'
class GetAssetsCommand(Command):
name = 'get-assets'
description = '''
This command downloads external extension dependencies used by Workload Automation.
Works by first downloading a directory index of the assets, then iterating through
it to get assets for the specified extensions.
'''
# Uses config setting if available otherwise defaults to ARM-software repo
# Can be overriden with the --url argument
assets_url = settings.remote_assets_url or REMOTE_ASSETS_URL
def initialize(self, context):
self.parser.add_argument('-f', '--force', action='store_true',
help='Always fetch the assets, even if matching versions exist in local cache.')
self.parser.add_argument('--url', metavar='URL', type=not_empty, default=self.assets_url,
help='''The location from which to download the files. If not provided,
config setting ``remote_assets_url`` will be used if available, else
uses the default REMOTE_ASSETS_URL parameter in the script.''')
group = self.parser.add_mutually_exclusive_group(required=True)
group.add_argument('-a', '--all', action='store_true',
help='Download assets for all extensions found in the index. Cannot be used with -e.')
group.add_argument('-e', dest='exts', metavar='EXT', nargs='+', type=not_empty,
help='One or more extensions whose assets to download. Cannot be used with --all.')
def execute(self, args):
self.logger.debug('Program arguments: {}'.format(vars(args)))
if args.force:
self.logger.info('Force-download of assets requested')
if not args.url:
self.logger.debug('URL not provided, falling back to default setting in config')
self.logger.info('Downloading external assets from {}'.format(args.url))
# Get file index of assets
ext_loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
getter = ext_loader.get_resource_getter('http_assets', None, url=args.url, always_fetch=args.force)
try:
getter.index = getter.fetch_index()
except (ConnectionError, RequestException) as e:
self.exit_with_error(str(e))
all_assets = dict()
for k, v in getter.index.iteritems():
all_assets[str(k)] = [str(asset['path']) for asset in v]
# Here we get a list of all extensions present in the current WA installation,
# and cross-check that against the list of extensions whose assets are requested.
# The aim is to avoid downloading assets for extensions that do not exist, since
# WA extensions and asset index can be updated independently and go out of sync.
all_extensions = [ext.name for ext in ext_loader.list_extensions()]
assets_to_get = set(all_assets).intersection(all_extensions)
if args.exts:
assets_to_get = assets_to_get.intersection(args.exts)
# Check list is not empty
if not assets_to_get:
if args.all:
self.exit_with_error('Could not find extensions: {}'.format(', '.join(all_assets.keys())))
else: # args.exts
self.exit_with_error('Asset index has no entries for: {}'.format(', '.join(args.exts)))
# Check out of sync extensions i.e. do not exist in both WA and assets index
missing = set(all_assets).difference(all_extensions) | set(args.exts or []).difference(all_assets)
if missing:
self.logger.warning('Not getting assets for missing extensions: {}'.format(', '.join(missing)))
# Ideally the extension loader would be used to instantiate, but it does full
# validation of the extension, like checking connected devices or supported
# platform(s). This info might be unavailable and is not required to download
# assets, since they are classified by extension name alone. So instead we use
# a simple subclass of ``Extension`` providing a valid ``name`` attribute.
for ext_name in assets_to_get:
owner = _instantiate(NamedExtension, ext_name)
self.logger.info('Getting assets for: {}'.format(ext_name))
for asset in all_assets[ext_name]:
getter.get(File(owner, asset)) # Download the files
def exit_with_error(self, message, code=1):
self.logger.error(message)
sys.exit(code)
class NamedExtension(Extension):
def __init__(self, name, **kwargs):
super(NamedExtension, self).__init__(**kwargs)
self.name = name
def not_empty(val):
if val:
return val
else:
raise argparse.ArgumentTypeError('Extension name cannot be blank')
def _instantiate(cls, *args, **kwargs):
return cls(*args, **kwargs)

@ -15,6 +15,8 @@
import os
import sys
import signal
from math import ceil
from wlauto import ExtensionLoader, Command, settings
from wlauto.common.resources import Executable
@ -22,40 +24,10 @@ from wlauto.core.resource import NO_ONE
from wlauto.core.resolver import ResourceResolver
from wlauto.core.configuration import RunConfiguration
from wlauto.core.agenda import Agenda
from wlauto.utils.revent import ReventRecording, GAMEPAD_MODE
class RecordCommand(Command):
name = 'record'
description = '''Performs a revent recording
This command helps making revent recordings. It will automatically
deploy revent and even has the option of automatically opening apps.
Revent allows you to record raw inputs such as screen swipes or button presses.
This can be useful for recording inputs for workloads such as games that don't
have XML UI layouts that can be used with UIAutomator. As a drawback from this,
revent recordings are specific to the device type they were recorded on.
WA uses two parts to the names of revent recordings in the format,
{device_name}.{suffix}.revent.
- device_name can either be specified manually with the ``-d`` argument or
it can be automatically determined. On Android device it will be obtained
from ``build.prop``, on Linux devices it is obtained from ``/proc/device-tree/model``.
- suffix is used by WA to determine which part of the app execution the
recording is for, currently these are either ``setup`` or ``run``. This
should be specified with the ``-s`` argument.
'''
def initialize(self, context):
self.context = context
self.parser.add_argument('-d', '--device', help='The name of the device')
self.parser.add_argument('-s', '--suffix', help='The suffix of the revent file, e.g. ``setup``')
self.parser.add_argument('-o', '--output', help='Directory to save the recording in')
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
action="store_true")
class ReventCommand(Command):
# Validate command options
def validate_args(self, args):
@ -89,21 +61,83 @@ class RecordCommand(Command):
self.device.initialize(context)
host_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
self.target_binary = self.device.install_if_needed(host_binary)
self.target_binary = self.device.install_executable(host_binary)
self.run(args)
def run(self, args):
raise NotImplementedError()
class RecordCommand(ReventCommand):
name = 'record'
description = '''Performs a revent recording
This command helps create revent recordings. It will automatically
deploy revent and even has the option of automatically opening apps.
Revent allows you to record raw inputs such as screen swipes or button presses.
This can be useful for recording inputs for workloads such as games that don't
have XML UI layouts that can be used with UIAutomator. As a drawback from this,
revent recordings are specific to the device type they were recorded on.
WA uses two parts to form the names of revent recordings in the format,
{device_name}.{suffix}.revent
- device_name can either be specified manually with the ``-d`` argument or
else the name of the device will be automatically determined. On an Android device it is obtained
from ``build.prop``, on Linux devices it is obtained from ``/proc/device-tree/model``.
- suffix is used by WA to determine which part of the app execution the
recording is for, currently either ``setup``, ``run`` or ``teardown``. This
should be specified with the ``-s`` argument.
**gamepad recording**
revent supports an alternative recording mode, where it will record events
from a single gamepad device. In this mode, revent will store the
description of this device as a part of the recording. When replaying such
a recording, revent will first create a virtual gamepad using the
description, and will replay the events into it, so a physical controller
does not need to be connected on replay. Unlike standard revent recordings,
recordings generated in this mode should be (to an extent) portable across
different devices.
note:
- The device on which a recording is being made in gamepad mode, must have
exactly one gamepad connected to it.
- The device on which a gamepad recording is being replayed must have
/dev/uinput enabled in the kernel (this interface is necessary to create
virtual gamepad).
'''
def initialize(self, context):
self.context = context
self.parser.add_argument('-d', '--device', help='The name of the device')
self.parser.add_argument('-s', '--suffix', help='The suffix of the revent file, e.g. ``setup``')
self.parser.add_argument('-o', '--output', help='Directory to save the recording in')
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
self.parser.add_argument('-g', '--gamepad', help='Record from a gamepad rather than all devices.',
action="store_true")
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
action="store_true")
self.parser.add_argument('-S', '--capture-screen', help='Record a screen capture after recording',
action="store_true")
def run(self, args):
if args.device:
self.device_name = args.device
device_name = args.device
else:
self.device_name = self.device.get_device_model()
device_name = self.device.get_device_model()
if args.suffix:
args.suffix += "."
revent_file = self.device.path.join(self.device.working_directory,
'{}.{}revent'.format(self.device_name, args.suffix or ""))
'{}.{}revent'.format(device_name, args.suffix or ""))
if args.clear:
self.device.execute("pm clear {}".format(args.package))
@ -114,18 +148,24 @@ class RecordCommand(Command):
self.logger.info("Press Enter when you are ready to record...")
raw_input("")
command = "{} record -t 100000 -s {}".format(self.target_binary, revent_file)
gamepad_flag = '-g ' if args.gamepad else ''
command = "{} record {}-s {}".format(self.target_binary, gamepad_flag, revent_file)
self.device.kick_off(command)
self.logger.info("Press Enter when you have finished recording...")
raw_input("")
self.device.killall("revent")
if args.capture_screen:
self.logger.info("Recording screen capture")
self.device.capture_screen(args.output or os.getcwdu())
self.device.killall("revent", signal.SIGINT)
self.logger.info("Waiting for revent to finish")
while self.device.get_pids_of("revent"):
pass
self.logger.info("Pulling files from device")
self.device.pull_file(revent_file, args.output or os.getcwdu())
class ReplayCommand(RecordCommand):
class ReplayCommand(ReventCommand):
name = 'replay'
description = '''Replay a revent recording
@ -154,8 +194,13 @@ class ReplayCommand(RecordCommand):
self.logger.info("Starting {}".format(args.package))
self.device.execute('monkey -p {} -c android.intent.category.LAUNCHER 1'.format(args.package))
self.logger.info("Replaying recording")
command = "{} replay {}".format(self.target_binary, revent_file)
self.device.execute(command)
recording = ReventRecording(args.revent)
timeout = ceil(recording.duration) + 30
recording.close()
self.device.execute(command, timeout=timeout,
as_root=(recording.mode == GAMEPAD_MODE))
self.logger.info("Finished replay")

@ -20,6 +20,7 @@ import shutil
import wlauto
from wlauto import Command, settings
from wlauto.exceptions import ConfigError
from wlauto.core.agenda import Agenda
from wlauto.core.execution import Executor
from wlauto.utils.log import add_log_file
@ -76,6 +77,11 @@ class RunCommand(Command):
agenda = Agenda(args.agenda)
settings.agenda = args.agenda
shutil.copy(args.agenda, settings.meta_directory)
if len(agenda.workloads) == 0:
raise ConfigError("No workloads specified")
elif '.' in args.agenda or os.sep in args.agenda:
raise ConfigError('Agenda "{}" does not exist.'.format(args.agenda))
else:
self.logger.debug('{} is not a file; assuming workload name.'.format(args.agenda))
agenda = Agenda()

@ -111,4 +111,3 @@ def format_extension_parameters(extension, out, width, shift=4):
param_texts.append(indent(param_text, shift))
out.write(format_column('\n'.join(param_texts), width))

@ -2,23 +2,30 @@ package ${package_name};
import android.app.Activity;
import android.os.Bundle;
import org.junit.Test;
import org.junit.runner.RunWith;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import android.view.KeyEvent;
// Import the uiautomator libraries
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.core.UiScrollable;
import com.android.uiautomator.core.UiSelector;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import com.arm.wlauto.uiauto.BaseUiAutomation;
public class UiAutomation extends BaseUiAutomation {
@RunWith(AndroidJUnit4.class)
public class UiAutomation extends BaseUiAutomation {
public static String TAG = "${name}";
public void runUiAutomation() throws Exception {
@Test
public void runUiAutomation() throws Exception {
initialize_instrumentation();
// UI Automation code goes here
}

@ -14,7 +14,7 @@ class ${class_name}(AndroidBenchmark):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

@ -14,7 +14,7 @@ class ${class_name}(AndroidUiAutoBenchmark):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

@ -8,7 +8,7 @@ class ${class_name}(Workload):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="${package_name}"
android:versionCode="1"
android:versionName="1.0">
<instrumentation
android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="${package_name}"/>
</manifest>

@ -0,0 +1,33 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 18
buildToolsVersion '25.0.0'
defaultConfig {
applicationId "${package_name}"
minSdkVersion 18
targetSdkVersion 25
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = file("$$project.buildDir/apk/${package_name}.apk")
}
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
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'
}
}

@ -0,0 +1,39 @@
#!/bin/bash
# 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 wlauto dist
libs_dir=app/libs
base_classes=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', '*.aar')"`
mkdir -p $$libs_dir
cp $$base_classes $$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)
rm -f ../$package_name
if [[ -f app/build/apk/$package_name.apk ]]; then
cp app/build/apk/$package_name.apk ../$package_name.apk
else
echo 'ERROR: UiAutomator apk could not be found!'
exit 9
fi

@ -0,0 +1,23 @@
// 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.1'
// 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
}

Binary file not shown.

@ -0,0 +1,6 @@
#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

@ -0,0 +1,160 @@
#!/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 "$@"

@ -0,0 +1,90 @@
@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

@ -0,0 +1 @@
include ':app'

@ -8,7 +8,7 @@ class ${class_name}(UiAutomatorWorkload):
parameters = [
# Workload parameters go here e.g.
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
Parameter('example_parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
description='This is an example parameter')
]

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -21,12 +21,16 @@ import time
import tempfile
import shutil
import threading
import json
import xml.dom.minidom
from subprocess import CalledProcessError
from wlauto.core.extension import Parameter
from wlauto.common.resources import Executable
from wlauto.core.resource import NO_ONE
from wlauto.common.linux.device import BaseLinuxDevice, PsEntry
from wlauto.exceptions import DeviceError, WorkerThreadError, TimeoutError, DeviceNotRespondingError
from wlauto.utils.misc import convert_new_lines
from wlauto.utils.misc import convert_new_lines, ABI_MAP, commonprefix
from wlauto.utils.types import boolean, regex
from wlauto.utils.android import (adb_shell, adb_background_shell, adb_list_devices,
adb_command, AndroidProperties, ANDROID_VERSION_MAP)
@ -49,9 +53,8 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
description='The unique ID of the device as output by "adb devices".'),
Parameter('android_prompt', kind=regex, default=re.compile('^.*(shell|root)@.*:/\S* [#$] ', re.MULTILINE),
description='The format of matching the shell prompt in Android.'),
Parameter('working_directory', default='/sdcard/wa-working',
description='Directory that will be used WA on the device for output files etc.'),
Parameter('binaries_directory', default='/data/local/tmp', override=True,
Parameter('working_directory', default='/sdcard/wa-working', override=True),
Parameter('binaries_directory', default='/data/local/tmp/wa-bin', override=True,
description='Location of binaries on the device.'),
Parameter('package_data_directory', default='/data/data',
description='Location of of data for an installed package (APK).'),
@ -105,19 +108,34 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
@property
def abi(self):
return self.getprop()['ro.product.cpu.abi'].split('-')[0]
val = self.getprop()['ro.product.cpu.abi'].split('-')[0]
for abi, architectures in ABI_MAP.iteritems():
if val in architectures:
return abi
return val
@property
def supported_eabi(self):
def supported_abi(self):
props = self.getprop()
result = [props['ro.product.cpu.abi']]
if 'ro.product.cpu.abi2' in props:
result.append(props['ro.product.cpu.abi2'])
if 'ro.product.cpu.abilist' in props:
for eabi in props['ro.product.cpu.abilist'].split(','):
if eabi not in result:
result.append(eabi)
return result
for abi in props['ro.product.cpu.abilist'].split(','):
if abi not in result:
result.append(abi)
mapped_result = []
for supported_abi in result:
for abi, architectures in ABI_MAP.iteritems():
found = False
if supported_abi in architectures and abi not in mapped_result:
mapped_result.append(abi)
found = True
break
if not found and supported_abi not in mapped_result:
mapped_result.append(supported_abi)
return mapped_result
def __init__(self, **kwargs):
super(AndroidDevice, self).__init__(**kwargs)
@ -193,6 +211,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
self._is_ready = True
def initialize(self, context):
self.sqlite = self.deploy_sqlite3(context) # pylint: disable=attribute-defined-outside-init
if self.is_rooted:
self.disable_screen_lock()
self.disable_selinux()
@ -258,6 +277,24 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
return line.split('=', 1)[1]
return None
def get_installed_package_abi(self, package):
"""
Returns the primary abi of the specified package if it is installed
on the device, or ``None`` otherwise.
"""
output = self.execute('dumpsys package {}'.format(package))
val = None
for line in convert_new_lines(output).split('\n'):
if 'primaryCpuAbi' in line:
val = line.split('=', 1)[1]
break
if val == 'null':
return None
for abi, architectures in ABI_MAP.iteritems():
if val in architectures:
return abi
return val
def list_packages(self):
"""
List packages installed on the device.
@ -338,7 +375,7 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
def delete_file(self, filepath, as_root=False): # pylint: disable=W0221
self._check_ready()
adb_shell(self.adb_name, "rm '{}'".format(filepath), as_root=as_root, timeout=self.default_timeout)
adb_shell(self.adb_name, "rm -rf '{}'".format(filepath), as_root=as_root, timeout=self.default_timeout)
def file_exists(self, filepath):
self._check_ready()
@ -346,18 +383,26 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
timeout=self.default_timeout)
return bool(int(output))
def install(self, filepath, timeout=default_timeout, with_name=None): # pylint: disable=W0221
def install(self, filepath, timeout=default_timeout, with_name=None, replace=False): # pylint: disable=W0221
ext = os.path.splitext(filepath)[1].lower()
if ext == '.apk':
return self.install_apk(filepath, timeout)
return self.install_apk(filepath, timeout, replace)
else:
return self.install_executable(filepath, with_name)
def install_apk(self, filepath, timeout=default_timeout): # pylint: disable=W0221
def install_apk(self, filepath, timeout=300, replace=False, allow_downgrade=False): # pylint: disable=W0221
self._check_ready()
ext = os.path.splitext(filepath)[1].lower()
if ext == '.apk':
return adb_command(self.adb_name, "install {}".format(filepath), timeout=timeout)
flags = []
if replace:
flags.append('-r') # Replace existing APK
if allow_downgrade:
flags.append('-d') # Install the APK even if a newer version is already installed
if self.get_sdk_version() >= 23:
flags.append('-g') # Grant all runtime permissions
self.logger.debug("Replace APK = {}, ADB flags = '{}'".format(replace, ' '.join(flags)))
return adb_command(self.adb_name, "install {} '{}'".format(' '.join(flags), filepath), timeout=timeout)
else:
raise DeviceError('Can\'t install {}: unsupported format.'.format(filepath))
@ -442,22 +487,20 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
else:
return adb_shell(self.adb_name, command, timeout, check_exit_code, as_root)
def kick_off(self, command):
def kick_off(self, command, as_root=None):
"""
Like execute but closes adb session and returns immediately, leaving the command running on the
device (this is different from execute(background=True) which keeps adb connection open and returns
a subprocess object).
.. note:: This relies on busybox's nohup applet and so won't work on unrooted devices.
Added in version 2.1.4
"""
if not self.is_rooted:
raise DeviceError('kick_off uses busybox\'s nohup applet and so can only be run a rooted device.')
if as_root is None:
as_root = self.is_rooted
try:
command = 'cd {} && busybox nohup {}'.format(self.working_directory, command)
output = self.execute(command, timeout=1, as_root=True)
command = 'cd {} && {} nohup {}'.format(self.working_directory, self.busybox, command)
output = self.execute(command, timeout=1, as_root=as_root)
except TimeoutError:
pass
else:
@ -465,8 +508,8 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
def get_pids_of(self, process_name):
"""Returns a list of PIDs of all processes with the specified name."""
result = self.execute('ps | {} grep {}'.format(self.busybox, process_name),
check_exit_code=False).strip()
result = (self.execute('ps | {} grep {}'.format(self.busybox, process_name),
check_exit_code=False) or '').strip()
if result and 'not found' not in result:
return [int(x.split()[1]) for x in result.split('\n')]
else:
@ -505,17 +548,17 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
def _get_android_properties(self, context):
props = {}
props['android_id'] = self.get_android_id()
buildprop_file = os.path.join(context.host_working_directory, 'build.prop')
if not os.path.isfile(buildprop_file):
self.pull_file('/system/build.prop', context.host_working_directory)
self._update_build_properties(buildprop_file, props)
context.add_run_artifact('build_properties', buildprop_file, 'export')
self._update_build_properties(props)
dumpsys_target_file = self.path.join(self.working_directory, 'window.dumpsys')
dumpsys_host_file = os.path.join(context.host_working_directory, 'window.dumpsys')
self.execute('{} > {}'.format('dumpsys window', dumpsys_target_file))
self.pull_file(dumpsys_target_file, dumpsys_host_file)
context.add_run_artifact('dumpsys_window', dumpsys_host_file, 'meta')
with open(dumpsys_host_file, 'w') as wfh:
wfh.write(self.execute('dumpsys window'))
context.add_run_artifact('dumpsys_window', dumpsys_host_file, 'meta')
prop_file = os.path.join(context.host_working_directory, 'android-props.json')
with open(prop_file, 'w') as wfh:
json.dump(props, wfh)
context.add_run_artifact('android_properties', prop_file, 'export')
return props
def getprop(self, prop=None):
@ -529,6 +572,11 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
return props[prop]
return props
def deploy_sqlite3(self, context):
host_file = context.resolver.get(Executable(NO_ONE, self.abi, 'sqlite3'))
target_file = self.install_if_needed(host_file)
return target_file
# Android-specific methods. These either rely on specifics of adb or other
# Android-only concepts in their interface and/or implementation.
@ -603,6 +651,17 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
self.pull_file(on_device_file, filepath)
self.delete_file(on_device_file)
def capture_ui_hierarchy(self, filepath):
"""Captures the current view hierarchy into the specified file in a XML format."""
on_device_file = self.path.join(self.working_directory, 'screen_capture.xml')
self.execute('uiautomator dump {}'.format(on_device_file))
self.pull_file(on_device_file, filepath)
self.delete_file(on_device_file)
parsed_xml = xml.dom.minidom.parse(filepath)
with open(filepath, 'w') as f:
f.write(parsed_xml.toprettyxml())
def is_screen_on(self):
"""Returns ``True`` if the device screen is currently on, ``False`` otherwise."""
output = self.execute('dumpsys power')
@ -629,7 +688,15 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
"""
lockdb = '/data/system/locksettings.db'
sqlcommand = "update locksettings set value='0' where name='screenlock.disabled';"
self.execute('sqlite3 {} "{}"'.format(lockdb, sqlcommand), as_root=True)
f = tempfile.NamedTemporaryFile()
try:
f.write('{} {} "{}"'.format(self.sqlite, lockdb, sqlcommand))
f.flush()
on_device_executable = self.install_executable(f.name,
with_name="disable_screen_lock")
finally:
f.close()
self.execute(on_device_executable, as_root=True)
def disable_selinux(self):
# This may be invoked from intialize() so we can't use execute() or the
@ -649,17 +716,41 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
except KeyError:
return None
# Internal methods: do not use outside of the class.
def refresh_device_files(self, file_list):
"""
Depending on the devices android version and root status, determine the
appropriate method of forcing a re-index of the mediaserver cache for a given
list of files.
"""
if self.device.is_rooted or self.device.get_sdk_version() < 24: # MM and below
common_path = commonprefix(file_list, sep=self.device.path.sep)
self.broadcast_media_mounted(common_path, self.device.is_rooted)
else:
for f in file_list:
self.broadcast_media_scan_file(f)
def _update_build_properties(self, filepath, props):
def broadcast_media_scan_file(self, filepath):
"""
Force a re-index of the mediaserver cache for the specified file.
"""
command = 'am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://'
self.execute(command + filepath)
def broadcast_media_mounted(self, dirpath, as_root=False):
"""
Force a re-index of the mediaserver cache for the specified directory.
"""
command = 'am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://'
self.execute(command + dirpath, as_root=as_root)
# Internal methods: do not use outside of the class.
def _update_build_properties(self, props):
try:
with open(filepath) as fh:
for line in fh:
line = re.sub(r'#.*', '', line).strip()
if not line:
continue
key, value = line.split('=', 1)
props[key] = value
regex = re.compile(r'\[([^\]]+)\]\s*:\s*\[([^\]]+)\]')
for match in regex.finditer(self.execute("getprop")):
key = match.group(1).strip()
value = match.group(2).strip()
props[key] = value
except ValueError:
self.logger.warning('Could not parse build.prop.')

@ -34,3 +34,13 @@ class JarFile(FileResource):
class ApkFile(FileResource):
name = 'apk'
def __init__(self, owner, platform=None, uiauto=False, package=None):
super(ApkFile, self).__init__(owner)
self.platform = platform
self.uiauto = uiauto
self.package = package
def __str__(self):
apk_type = 'uiautomator ' if self.uiauto else ''
return '<{}\'s {} {}APK>'.format(self.owner, self.platform, apk_type)

Binary file not shown.

586
wlauto/common/android/workload.py Normal file → Executable file

@ -17,27 +17,37 @@ import os
import sys
import time
from wlauto.core.extension import Parameter
from distutils.version import LooseVersion
from wlauto.core.extension import Parameter, ExtensionMeta, ListCollection
from wlauto.core.workload import Workload
from wlauto.core.resource import NO_ONE
from wlauto.common.resources import ExtensionAsset, Executable
from wlauto.exceptions import WorkloadError, ResourceError, ConfigError
from wlauto.utils.android import ApkInfo, ANDROID_NORMAL_PERMISSIONS
from wlauto.utils.types import boolean
import wlauto.common.android.resources
from wlauto.common.android.resources import ApkFile
from wlauto.common.resources import ExtensionAsset, File
from wlauto.exceptions import WorkloadError, ResourceError, DeviceError
from wlauto.utils.android import (ApkInfo, ANDROID_NORMAL_PERMISSIONS,
ANDROID_UNCHANGEABLE_PERMISSIONS, UNSUPPORTED_PACKAGES)
from wlauto.utils.types import boolean, ParameterDict
import wlauto.utils.statedetect as state_detector
from wlauto.common.linux.workload import ReventWorkload
DELAY = 5
# Due to the way `super` works you have to call it at every level but WA executes some
# methods conditionally and so has to call them directly via the class, this breaks super
# and causes it to run things mutiple times ect. As a work around for this untill workloads
# are reworked everything that subclasses workload calls parent methods explicitly
class UiAutomatorWorkload(Workload):
"""
Base class for all workloads that rely on a UI Automator JAR file.
Base class for all workloads that rely on a UI Automator APK file.
This class should be subclassed by workloads that rely on android UiAutomator
to work. This class handles transferring the UI Automator JAR file to the device
and invoking it to run the workload. By default, it will look for the JAR file in
the same directory as the .py file for the workload (this can be changed by overriding
to work. This class handles installing the UI Automator APK to the device
and invoking it to run the workload. By default, it will look for the ``*.apk`` file
in the same directory as the .py file for the workload (this can be changed by overriding
the ``uiauto_file`` property in the subclassing workload).
To inintiate UI Automation, the fully-qualified name of the Java class and the
@ -49,7 +59,7 @@ class UiAutomatorWorkload(Workload):
match what is expected, or you could override ``uiauto_package``, ``uiauto_class`` and
``uiauto_method`` class attributes with the value that match your Java code.
You can also pass parameters to the JAR file. To do this add the parameters to
You can also pass parameters to the APK file. To do this add the parameters to
``self.uiauto_params`` dict inside your class's ``__init__`` or ``setup`` methods.
"""
@ -58,38 +68,43 @@ class UiAutomatorWorkload(Workload):
uiauto_package = ''
uiauto_class = 'UiAutomation'
uiauto_method = 'runUiAutomation'
uiauto_method = 'android.support.test.runner.AndroidJUnitRunner'
# Can be overidden by subclasses to adjust to run time of specific
# benchmarks.
run_timeout = 4 * 60 # seconds
run_timeout = 10 * 60 # seconds
uninstall_uiauto_apk = True
def __init__(self, device, _call_super=True, **kwargs): # pylint: disable=W0613
if _call_super:
super(UiAutomatorWorkload, self).__init__(device, **kwargs)
Workload.__init__(self, device, **kwargs)
self.uiauto_file = None
self.device_uiauto_file = None
self.command = None
self.uiauto_params = {}
self.uiauto_params = ParameterDict()
def init_resources(self, context):
self.uiauto_file = context.resolver.get(wlauto.common.android.resources.JarFile(self))
self.uiauto_file = context.resolver.get(ApkFile(self, uiauto=True))
if not self.uiauto_file:
raise ResourceError('No UI automation JAR file found for workload {}.'.format(self.name))
self.device_uiauto_file = self.device.path.join(self.device.working_directory,
os.path.basename(self.uiauto_file))
raise ResourceError('No UI automation APK file found for workload {}.'.format(self.name))
if not self.uiauto_package:
self.uiauto_package = os.path.splitext(os.path.basename(self.uiauto_file))[0]
def setup(self, context):
method_string = '{}.{}#{}'.format(self.uiauto_package, self.uiauto_class, self.uiauto_method)
Workload.setup(self, context)
params_dict = self.uiauto_params
params_dict['workdir'] = self.device.working_directory
params = ''
for k, v in self.uiauto_params.iteritems():
params += ' -e {} {}'.format(k, v)
self.command = 'uiautomator runtest {}{} -c {}'.format(self.device_uiauto_file, params, method_string)
self.device.push_file(self.uiauto_file, self.device_uiauto_file)
for k, v in self.uiauto_params.iter_encoded_items():
params += ' -e {} "{}"'.format(k, v)
if self.device.package_is_installed(self.uiauto_package):
self.device.uninstall(self.uiauto_package)
self.device.install_apk(self.uiauto_file)
instrumention_string = 'am instrument -w -r {} -e class {}.{} {}/{}'
self.command = instrumention_string.format(params, self.uiauto_package,
self.uiauto_class, self.uiauto_package,
self.uiauto_method)
self.device.killall('uiautomator')
def run(self, context):
@ -104,11 +119,12 @@ class UiAutomatorWorkload(Workload):
pass
def teardown(self, context):
self.device.delete_file(self.device_uiauto_file)
if self.uninstall_uiauto_apk:
self.device.uninstall(self.uiauto_package)
def validate(self):
if not self.uiauto_file:
raise WorkloadError('No UI automation JAR file found for workload {}.'.format(self.name))
raise WorkloadError('No UI automation APK file found for workload {}.'.format(self.name))
if not self.uiauto_package:
raise WorkloadError('No UI automation package specified for workload {}.'.format(self.name))
@ -122,10 +138,16 @@ class ApkWorkload(Workload):
:package: The package name of the app. This is usually a Java-style name of the form
``com.companyname.appname``.
:activity: This is the initial activity of the app. This will be used to launch the
app during the setup.
app during the setup. Many applications do not specify a launch activity so
this may be left blank if necessary.
:view: The class of the main view pane of the app. This needs to be defined in order
to collect SurfaceFlinger-derived statistics (such as FPS) for the app, but
may otherwise be left as ``None``.
:launch_main: If ``False``, the default activity will not be launched (during setup),
allowing workloads to start the app with an intent of their choice in
the run step. This is useful for apps without a launchable default/main
activity or those where it cannot be launched without intent data (which
is provided at the run phase).
:install_timeout: Timeout for the installation of the APK. This may vary wildly based on
the size and nature of a specific APK, and so should be defined on
per-workload basis.
@ -135,6 +157,9 @@ class ApkWorkload(Workload):
so, as with all timeouts, so leeway must be included in
the specified value.
:min_apk_version: The minimum supported apk version for this workload. May be ``None``.
:max_apk_version: The maximum supported apk version for this workload. May be ``None``.
.. note:: Both package and activity for a workload may be obtained from the APK using
the ``aapt`` tool that comes with the ADT (Android Developemnt Tools) bundle.
@ -142,91 +167,241 @@ class ApkWorkload(Workload):
package = None
activity = None
view = None
min_apk_version = None
max_apk_version = None
supported_platforms = ['android']
launch_main = True
parameters = [
Parameter('install_timeout', kind=int, default=300,
description='Timeout for the installation of the apk.'),
Parameter('check_apk', kind=boolean, default=True,
description='''
Discover the APK for this workload on the host, and check that
the version matches the one on device (if already installed).
When set to True the APK file on the host will be prefered if
it is a valid version and ABI, if not it will fall back to the
version on the targer. When set to False the target version is
prefered.
'''),
Parameter('force_install', kind=boolean, default=False,
description='''
Always re-install the APK, even if matching version is found
on already installed on the device.
Always re-install the APK, even if matching version is found already installed
on the device. Runs ``adb install -r`` to ensure existing APK is replaced. When
this is set, check_apk is ignored.
'''),
Parameter('uninstall_apk', kind=boolean, default=False,
description='If ``True``, will uninstall workload\'s APK as part of teardown.'),
Parameter('exact_abi', kind=bool, default=False,
description='''
If ``True``, workload will check that the APK matches the target
device ABI, otherwise any APK found will be used.
'''),
Parameter('clear_data_on_reset', kind=bool, default=True,
description="""
If set to ``False``, this will prevent WA from clearing package
data for this workload prior to running it.
"""),
]
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
super(ApkWorkload, self).__init__(device, **kwargs)
Workload.__init__(self, device, **kwargs)
self.apk_file = None
self.apk_version = None
self.logcat_log = None
self.exact_apk_version = None
def init_resources(self, context):
self.apk_file = context.resolver.get(wlauto.common.android.resources.ApkFile(self),
version=getattr(self, 'version', None),
strict=self.check_apk)
def validate(self):
if self.check_apk:
if not self.apk_file:
raise WorkloadError('No APK file found for workload {}.'.format(self.name))
else:
if self.force_install:
raise ConfigError('force_install cannot be "True" when check_apk is set to "False".')
def setup(self, context):
self.initialize_package(context)
self.start_activity()
self.device.execute('am kill-all') # kill all *background* activities
def setup(self, context): # pylint: disable=too-many-branches
Workload.setup(self, context)
self.setup_workload_apk(context)
self.launch_application()
self.kill_background()
self.device.clear_logcat()
def initialize_package(self, context):
installed_version = self.device.get_installed_package_version(self.package)
if self.check_apk:
self.initialize_with_host_apk(context, installed_version)
else:
if not installed_version:
message = '''{} not found found on the device and check_apk is set to "False"
so host version was not checked.'''
raise WorkloadError(message.format(self.package))
message = 'Version {} installed on device; skipping host APK check.'
self.logger.debug(message.format(installed_version))
self.reset(context)
self.apk_version = installed_version
def setup_workload_apk(self, context):
# Get target version
target_version = self.device.get_installed_package_version(self.package)
if target_version:
target_version = LooseVersion(target_version)
self.logger.debug("Found version '{}' on target device".format(target_version))
# Get host version
self.apk_file = context.resolver.get(ApkFile(self, self.device.abi,
package=getattr(self, 'package', None)),
version=getattr(self, 'version', None),
variant_name=getattr(self, 'variant_name', None),
strict=False)
# Get target abi
target_abi = self.device.get_installed_package_abi(self.package)
if target_abi:
self.logger.debug("Found apk with primary abi '{}' on target device".format(target_abi))
# Get host version, primary abi is first, and then try to find supported.
for abi in self.device.supported_abi:
self.apk_file = context.resolver.get(ApkFile(self, abi,
package=getattr(self, 'package', None)),
version=getattr(self, 'version', None),
variant_name=getattr(self, 'variant_name', None),
strict=False)
# Stop if apk found, or if exact_abi is set only look for primary abi.
if self.apk_file or self.exact_abi:
break
host_version = self.check_host_version()
self.verify_apk_version(target_version, target_abi, host_version)
def initialize_with_host_apk(self, context, installed_version):
host_version = ApkInfo(self.apk_file).version_name
if installed_version != host_version:
if installed_version:
message = '{} host version: {}, device version: {}; re-installing...'
self.logger.debug(message.format(os.path.basename(self.apk_file),
host_version, installed_version))
else:
message = '{} host version: {}, not found on device; installing...'
self.logger.debug(message.format(os.path.basename(self.apk_file),
host_version))
self.force_install = True # pylint: disable=attribute-defined-outside-init
else:
message = '{} version {} found on both device and host.'
self.logger.debug(message.format(os.path.basename(self.apk_file),
host_version))
if self.force_install:
if installed_version:
self.device.uninstall(self.package)
self.install_apk(context)
self.force_install_apk(context, host_version)
elif self.check_apk:
self.prefer_host_apk(context, host_version, target_version)
else:
self.reset(context)
self.apk_version = host_version
self.prefer_target_apk(context, host_version, target_version)
def start_activity(self):
output = self.device.execute('am start -W -n {}/{}'.format(self.package, self.activity))
self.reset(context)
self.apk_version = self.device.get_installed_package_version(self.package)
context.add_classifiers(apk_version=self.apk_version)
def check_host_version(self):
host_version = None
if self.apk_file is not None:
host_version = ApkInfo(self.apk_file).version_name
if host_version:
host_version = LooseVersion(host_version)
self.logger.debug("Found version '{}' on host".format(host_version))
return host_version
def verify_apk_version(self, target_version, target_abi, host_version):
# Error if apk was not found anywhere
if target_version is None and host_version is None:
msg = "Could not find APK for '{}' on the host or target device"
raise ResourceError(msg.format(self.name))
if self.exact_apk_version is not None:
if self.exact_apk_version != target_version and self.exact_apk_version != host_version:
msg = "APK version '{}' not found on the host '{}' or target '{}'"
raise ResourceError(msg.format(self.exact_apk_version, host_version, target_version))
# Error if exact_abi and suitable apk not found on host and incorrect version on device
if self.exact_abi and host_version is None:
if target_abi != self.device.abi:
msg = "APK abi '{}' not found on the host and target is '{}'"
raise ResourceError(msg.format(self.device.abi, target_abi))
def launch_application(self):
if self.launch_main:
self.launch_package() # launch default activity without intent data
def kill_background(self):
self.device.execute('am kill-all') # kill all *background* activities
def force_install_apk(self, context, host_version):
if host_version is None:
raise ResourceError("force_install is 'True' but could not find APK on the host")
try:
self.validate_version(host_version)
except ResourceError as e:
msg = "force_install is 'True' but the host version is invalid:\n\t{}"
raise ResourceError(msg.format(str(e)))
self.install_apk(context, replace=True)
def prefer_host_apk(self, context, host_version, target_version):
msg = "check_apk is 'True' "
if host_version is None:
try:
self.validate_version(target_version)
except ResourceError as e:
msg += "but the APK was not found on the host and the target version is invalid:\n\t{}"
raise ResourceError(msg.format(str(e)))
else:
msg += "but the APK was not found on the host, using target version"
self.logger.debug(msg)
return
try:
self.validate_version(host_version)
except ResourceError as e1:
msg += "but the host APK version is invalid:\n\t{}\n"
if target_version is None:
msg += "The target does not have the app either"
raise ResourceError(msg.format(str(e1)))
try:
self.validate_version(target_version)
except ResourceError as e2:
msg += "The target version is also invalid:\n\t{}"
raise ResourceError(msg.format(str(e1), str(e2)))
else:
msg += "using the target version instead"
self.logger.debug(msg.format(str(e1)))
else: # Host version is valid
if target_version is not None and target_version == host_version:
msg += " and a matching version is alread on the device, doing nothing"
self.logger.debug(msg)
return
msg += " and the host version is not on the target, installing APK"
self.logger.debug(msg)
self.install_apk(context, replace=True)
def prefer_target_apk(self, context, host_version, target_version):
msg = "check_apk is 'False' "
if target_version is None:
try:
self.validate_version(host_version)
except ResourceError as e:
msg += "but the app was not found on the target and the host version is invalid:\n\t{}"
raise ResourceError(msg.format(str(e)))
else:
msg += "and the app was not found on the target, using host version"
self.logger.debug(msg)
self.install_apk(context)
return
try:
self.validate_version(target_version)
except ResourceError as e1:
msg += "but the target app version is invalid:\n\t{}\n"
if host_version is None:
msg += "The host does not have the APK either"
raise ResourceError(msg.format(str(e1)))
try:
self.validate_version(host_version)
except ResourceError as e2:
msg += "The host version is also invalid:\n\t{}"
raise ResourceError(msg.format(str(e1), str(e2)))
else:
msg += "Using the host APK instead"
self.logger.debug(msg.format(str(e1)))
self.install_apk(context, replace=True)
else:
msg += "and a valid version of the app is already on the target, using target app"
self.logger.debug(msg)
def validate_version(self, version):
min_apk_version = getattr(self, 'min_apk_version', None)
max_apk_version = getattr(self, 'max_apk_version', None)
if min_apk_version is not None and max_apk_version is not None:
if version < LooseVersion(min_apk_version) or \
version > LooseVersion(max_apk_version):
msg = "version '{}' not supported. " \
"Minimum version required: '{}', Maximum version known to work: '{}'"
raise ResourceError(msg.format(version, min_apk_version, max_apk_version))
elif min_apk_version is not None:
if version < LooseVersion(min_apk_version):
msg = "version '{}' not supported. " \
"Minimum version required: '{}'"
raise ResourceError(msg.format(version, min_apk_version))
elif max_apk_version is not None:
if version > LooseVersion(max_apk_version):
msg = "version '{}' not supported. " \
"Maximum version known to work: '{}'"
raise ResourceError(msg.format(version, max_apk_version))
def launch_package(self):
if not self.activity:
output = self.device.execute('am start -W {}'.format(self.package))
else:
output = self.device.execute('am start -W -n {}/{}'.format(self.package, self.activity))
if 'Error:' in output:
self.device.execute('am force-stop {}'.format(self.package)) # this will dismiss any erro dialogs
raise WorkloadError(output)
@ -234,23 +409,32 @@ class ApkWorkload(Workload):
def reset(self, context): # pylint: disable=W0613
self.device.execute('am force-stop {}'.format(self.package))
self.device.execute('pm clear {}'.format(self.package))
if self.clear_data_on_reset:
self.device.execute('pm clear {}'.format(self.package))
# As of android API level 23, apps can request permissions at runtime,
# this will grant all of them so requests do not pop up when running the app
# This can also be done less "manually" during adb install using the -g flag
if self.device.get_sdk_version() >= 23:
self._grant_requested_permissions()
def install_apk(self, context):
output = self.device.install(self.apk_file, self.install_timeout)
def install_apk(self, context, replace=False):
success = False
if replace and self.device.package_is_installed(self.package):
self.device.uninstall(self.package)
output = self.device.install_apk(self.apk_file, timeout=self.install_timeout,
replace=replace, allow_downgrade=True)
if 'Failure' in output:
if 'ALREADY_EXISTS' in output:
self.logger.warn('Using already installed APK (did not unistall properly?)')
self.reset(context)
else:
raise WorkloadError(output)
else:
self.logger.debug(output)
success = True
self.do_post_install(context)
return success
def _grant_requested_permissions(self):
dumpsys_output = self.device.execute(command="dumpsys package {}".format(self.package))
@ -263,17 +447,29 @@ class ApkWorkload(Workload):
for line in lines:
if "android.permission." in line:
permissions.append(line.split(":")[0].strip())
else:
# Matching either of these means the end of requested permissions section
elif "install permissions:" in line or "runtime permissions:" in line:
break
for permission in permissions:
for permission in set(permissions):
# "Normal" Permisions are automatically granted and cannot be changed
permission_name = permission.rsplit('.', 1)[1]
if permission_name not in ANDROID_NORMAL_PERMISSIONS:
self.device.execute("pm grant {} {}".format(self.package, permission))
# Some permissions are not allowed to be "changed"
if permission_name not in ANDROID_UNCHANGEABLE_PERMISSIONS:
# On some API 23+ devices, this may fail with a SecurityException
# on previously granted permissions. In that case, just skip as it
# is not fatal to the workload execution
try:
self.device.execute("pm grant {} {}".format(self.package, permission))
except DeviceError as e:
if "changeable permission" in e.message or "Unknown permission" in e.message:
self.logger.debug(e)
else:
raise e
def do_post_install(self, context):
""" May be overwritten by dervied classes."""
""" May be overwritten by derived classes."""
pass
def run(self, context):
@ -292,71 +488,8 @@ class ApkWorkload(Workload):
if self.uninstall_apk:
self.device.uninstall(self.package)
AndroidBenchmark = ApkWorkload # backward compatibility
class ReventWorkload(Workload):
default_setup_timeout = 5 * 60 # in seconds
default_run_timeout = 10 * 60 # in seconds
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
super(ReventWorkload, self).__init__(device, **kwargs)
devpath = self.device.path
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
self.on_device_setup_revent = devpath.join(self.device.working_directory, '{}.setup.revent'.format(self.device.name))
self.on_device_run_revent = devpath.join(self.device.working_directory, '{}.run.revent'.format(self.device.name))
self.setup_timeout = kwargs.get('setup_timeout', self.default_setup_timeout)
self.run_timeout = kwargs.get('run_timeout', self.default_run_timeout)
self.revent_setup_file = None
self.revent_run_file = None
def init_resources(self, context):
self.revent_setup_file = context.resolver.get(wlauto.common.android.resources.ReventFile(self, 'setup'))
self.revent_run_file = context.resolver.get(wlauto.common.android.resources.ReventFile(self, 'run'))
def setup(self, context):
self._check_revent_files(context)
self.device.killall('revent')
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_setup_revent)
self.device.execute(command, timeout=self.setup_timeout)
def run(self, context):
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_run_revent)
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_device_run_revent)))
self.device.execute(command, timeout=self.run_timeout)
self.logger.debug('Replay completed.')
def update_result(self, context):
pass
def teardown(self, context):
self.device.delete_file(self.on_device_setup_revent)
self.device.delete_file(self.on_device_run_revent)
def _check_revent_files(self, context):
# check the revent binary
revent_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
if not os.path.isfile(revent_binary):
message = '{} does not exist. '.format(revent_binary)
message += 'Please build revent for your system and place it in that location'
raise WorkloadError(message)
if not self.revent_setup_file:
# pylint: disable=too-few-format-args
message = '{0}.setup.revent file does not exist, Please provide one for your device, {0}'.format(self.device.name)
raise WorkloadError(message)
if not self.revent_run_file:
# pylint: disable=too-few-format-args
message = '{0}.run.revent file does not exist, Please provide one for your device, {0}'.format(self.device.name)
raise WorkloadError(message)
self.on_device_revent_binary = self.device.install_executable(revent_binary)
self.device.push_file(self.revent_run_file, self.on_device_run_revent)
self.device.push_file(self.revent_setup_file, self.on_device_setup_revent)
class AndroidUiAutoBenchmark(UiAutomatorWorkload, AndroidBenchmark):
supported_platforms = ['android']
@ -365,6 +498,11 @@ class AndroidUiAutoBenchmark(UiAutomatorWorkload, AndroidBenchmark):
UiAutomatorWorkload.__init__(self, device, **kwargs)
AndroidBenchmark.__init__(self, device, _call_super=False, **kwargs)
def initialize(self, context):
UiAutomatorWorkload.initialize(self, context)
AndroidBenchmark.initialize(self, context)
self._check_unsupported_packages()
def init_resources(self, context):
UiAutomatorWorkload.init_resources(self, context)
AndroidBenchmark.init_resources(self, context)
@ -381,6 +519,98 @@ class AndroidUiAutoBenchmark(UiAutomatorWorkload, AndroidBenchmark):
UiAutomatorWorkload.teardown(self, context)
AndroidBenchmark.teardown(self, context)
def _check_unsupported_packages(self):
"""
Check for any unsupported package versions and raise an
exception if detected.
"""
for package in UNSUPPORTED_PACKAGES:
version = self.device.get_installed_package_version(package)
if version is None:
continue
if '-' in version:
version = version.split('-')[0] # ignore abi version
if version in UNSUPPORTED_PACKAGES[package]:
message = 'This workload does not support version "{}" of package "{}"'
raise WorkloadError(message.format(version, package))
class AndroidUxPerfWorkloadMeta(ExtensionMeta):
to_propagate = ExtensionMeta.to_propagate + [('deployable_assets', str, ListCollection)]
class AndroidUxPerfWorkload(AndroidUiAutoBenchmark):
__metaclass__ = AndroidUxPerfWorkloadMeta
deployable_assets = []
parameters = [
Parameter('markers_enabled', kind=bool, default=False,
description="""
If ``True``, UX_PERF action markers will be emitted to logcat during
the test run.
"""),
Parameter('clean_assets', kind=bool, default=False,
description="""
If ``True`` pushed assets will be deleted at the end of each iteration
"""),
Parameter('force_push_assets', kind=bool, default=False,
description="""
If ``True`` always push assets on each iteration, even if the
assets already exists in the device path
"""),
]
def _path_on_device(self, fpath, dirname=None):
if dirname is None:
dirname = self.device.working_directory
fname = os.path.basename(fpath)
return self.device.path.join(dirname, fname)
def push_assets(self, context):
pushed = False
file_list = []
for f in self.deployable_assets:
fpath = context.resolver.get(File(self, f))
device_path = self._path_on_device(fpath)
if self.force_push_assets or not self.device.file_exists(device_path):
self.device.push_file(fpath, device_path, timeout=300)
file_list.append(device_path)
pushed = True
if pushed:
self.device.refresh_device_files(file_list)
def delete_assets(self):
if self.deployable_assets:
file_list = []
for f in self.deployable_assets:
f = self._path_on_device(f)
self.device.delete_file(f)
file_list.append(f)
self.device.delete_file(f)
self.device.refresh_device_files(file_list)
def __init__(self, device, **kwargs):
super(AndroidUxPerfWorkload, self).__init__(device, **kwargs)
# Turn class attribute into instance attribute
self.deployable_assets = list(self.deployable_assets)
def validate(self):
super(AndroidUxPerfWorkload, self).validate()
self.uiauto_params['package_name'] = self.package
self.uiauto_params['markers_enabled'] = self.markers_enabled
def setup(self, context):
super(AndroidUxPerfWorkload, self).setup(context)
self.push_assets(context)
def teardown(self, context):
super(AndroidUxPerfWorkload, self).teardown(context)
if self.clean_assets:
self.delete_assets()
class GameWorkload(ApkWorkload, ReventWorkload):
"""
@ -414,21 +644,22 @@ class GameWorkload(ApkWorkload, ReventWorkload):
view = 'SurfaceView'
loading_time = 10
supported_platforms = ['android']
setup_required = True
parameters = [
Parameter('install_timeout', default=500, override=True),
Parameter('check_states', kind=bool, default=False, global_alias='check_game_states',
description="""Use visual state detection to verify the state of the workload
after setup and run"""),
Parameter('assets_push_timeout', kind=int, default=500,
description='Timeout used during deployment of the assets package (if there is one).'),
Parameter('clear_data_on_reset', kind=bool, default=True,
description="""
If set to ``False``, this will prevent WA from clearing package
data for this workload prior to running it.
"""),
]
def __init__(self, device, **kwargs): # pylint: disable=W0613
ApkWorkload.__init__(self, device, **kwargs)
ReventWorkload.__init__(self, device, _call_super=False, **kwargs)
if self.check_states:
state_detector.check_match_state_dependencies()
self.logcat_process = None
self.module_dir = os.path.dirname(sys.modules[self.__module__].__file__)
self.revent_dir = os.path.join(self.module_dir, 'revent_files')
@ -436,6 +667,8 @@ class GameWorkload(ApkWorkload, ReventWorkload):
def init_resources(self, context):
ApkWorkload.init_resources(self, context)
ReventWorkload.init_resources(self, context)
if self.check_states:
self._check_statedetection_files(context)
def setup(self, context):
ApkWorkload.setup(self, context)
@ -443,6 +676,10 @@ class GameWorkload(ApkWorkload, ReventWorkload):
time.sleep(self.loading_time)
ReventWorkload.setup(self, context)
# state detection check if it's enabled in the config
if self.check_states:
self.check_state(context, "setup_complete")
def do_post_install(self, context):
ApkWorkload.do_post_install(self, context)
self._deploy_assets(context, self.assets_push_timeout)
@ -462,6 +699,10 @@ class GameWorkload(ApkWorkload, ReventWorkload):
ReventWorkload.run(self, context)
def teardown(self, context):
# state detection check if it's enabled in the config
if self.check_states:
self.check_state(context, "run_complete")
if not self.saved_state_file:
ApkWorkload.teardown(self, context)
else:
@ -493,3 +734,22 @@ class GameWorkload(ApkWorkload, ReventWorkload):
self.device.busybox,
ondevice_cache)
self.device.execute(deploy_command, timeout=timeout, as_root=True)
def _check_statedetection_files(self, context):
try:
self.statedefs_dir = context.resolver.get(File(self, 'state_definitions'))
except ResourceError:
self.logger.warning("State definitions directory not found. Disabling state detection.")
self.check_states = False # pylint: disable=W0201
def check_state(self, context, phase):
try:
self.logger.info("\tChecking workload state...")
screenshotPath = os.path.join(context.output_directory, "screen.png")
self.device.capture_screen(screenshotPath)
stateCheck = state_detector.verify_state(screenshotPath, self.statedefs_dir, phase)
if not stateCheck:
raise WorkloadError("Unexpected state after setup")
except state_detector.StateDefinitionError as e:
msg = "State definitions or template files missing or invalid ({}). Skipping state detection."
self.logger.warning(msg.format(e.message))

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -462,7 +462,7 @@ class BaseGem5Device(object):
# gem5 might be slow. Hence, we need to make the ping timeout very long.
def ping(self):
self.logger.debug("Pinging gem5 to see if it is still alive")
self.gem5_shell('ls /', timeout=self.longdelay)
self.gem5_shell('ls /', timeout=self.long_delay)
# Additional Android-specific methods.
def forward_port(self, _): # pylint: disable=R0201

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -17,6 +17,7 @@
import os
import re
import time
import base64
import socket
from collections import namedtuple
from subprocess import CalledProcessError
@ -39,6 +40,8 @@ FstabEntry = namedtuple('FstabEntry', ['device', 'mount_point', 'fs_type', 'opti
PsEntry = namedtuple('PsEntry', 'user pid ppid vsize rss wchan pc state name')
LsmodEntry = namedtuple('LsmodEntry', ['name', 'size', 'use_count', 'used_by'])
GOOGLE_DNS_SERVER_ADDRESS = '8.8.8.8'
class BaseLinuxDevice(Device): # pylint: disable=abstract-method
@ -92,12 +95,18 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
'''),
Parameter('binaries_directory',
description='Location of executable binaries on this device (must be in PATH).'),
Parameter('working_directory',
description='''
Working directory to be used by WA. This must be in a location where the specified user
has write permissions. This will default to /home/<username>/wa (or to /root/wa, if
username is 'root').
'''),
]
runtime_parameters = [
RuntimeParameter('sysfile_values', 'get_sysfile_values', 'set_sysfile_values', value_name='params'),
CoreParameter('${core}_cores', 'get_number_of_online_cpus', 'set_number_of_online_cpus',
CoreParameter('${core}_cores', 'get_number_of_online_cores', 'set_number_of_online_cores',
value_name='number'),
CoreParameter('${core}_min_frequency', 'get_core_min_frequency', 'set_core_min_frequency',
value_name='freq'),
@ -128,6 +137,10 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
self._abi = val
return self._abi
@property
def supported_abi(self):
return [self.abi]
@property
def online_cpus(self):
val = self.get_sysfile_value('/sys/devices/system/cpu/online')
@ -214,7 +227,10 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
outfile = os.path.join(context.host_working_directory, normname)
if self.is_file(propfile):
with open(outfile, 'w') as wfh:
wfh.write(self.execute('cat {}'.format(propfile)))
if propfile.endswith(".gz"):
wfh.write(self.execute('{} zcat {}'.format(self.busybox, propfile)))
else:
wfh.write(self.execute('cat {}'.format(propfile)))
elif self.is_directory(propfile):
self.pull_file(propfile, outfile)
else:
@ -226,7 +242,7 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
self.logger.debug('Could not pull property file "{}"'.format(propfile))
return {}
def get_sysfile_value(self, sysfile, kind=None):
def get_sysfile_value(self, sysfile, kind=None, binary=False):
"""
Get the contents of the specified sysfile.
@ -236,28 +252,49 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
be any Python callable that takes a single str argument.
If not specified or is None, the contents will be returned
as a string.
:param binary: Whether the value should be encoded into base64 for reading
to deal with binary format.
"""
output = self.execute('cat \'{}\''.format(sysfile), as_root=self.is_rooted).strip() # pylint: disable=E1103
if binary:
output = self.execute('{} base64 {}'.format(self.busybox, sysfile), as_root=self.is_rooted).strip()
output = output.decode('base64')
else:
output = self.execute('cat \'{}\''.format(sysfile), as_root=self.is_rooted).strip() # pylint: disable=E1103
if kind:
return kind(output)
else:
return output
def set_sysfile_value(self, sysfile, value, verify=True):
def set_sysfile_value(self, sysfile, value, verify=True, binary=False):
"""
Set the value of the specified sysfile. By default, the value will be checked afterwards.
Can be overridden by setting ``verify`` parameter to ``False``.
Can be overridden by setting ``verify`` parameter to ``False``. By default binary values
will not be written correctly this can be changed by setting the ``binary`` parameter to
``True``.
"""
value = str(value)
self.execute('echo {} > \'{}\''.format(value, sysfile), check_exit_code=False, as_root=True)
if binary:
# Value is already string encoded, so need to decode before encoding in base64
try:
value = str(value.decode('string_escape'))
except ValueError as e:
msg = 'Can not interpret value "{}" for "{}": {}'
raise ValueError(msg.format(value, sysfile, e.message))
encoded_value = base64.b64encode(value)
cmd = 'echo {} | {} base64 -d > \'{}\''.format(encoded_value, self.busybox, sysfile)
else:
cmd = 'echo {} > \'{}\''.format(value, sysfile)
self.execute(cmd, check_exit_code=False, as_root=True)
if verify:
output = self.get_sysfile_value(sysfile)
output = self.get_sysfile_value(sysfile, binary=binary)
if output.strip() != value: # pylint: disable=E1103
message = 'Could not set the value of {} to {}'.format(sysfile, value)
raise DeviceError(message)
self._written_sysfiles.append(sysfile)
self._written_sysfiles.append((sysfile, binary))
def get_sysfile_values(self):
"""
@ -266,21 +303,24 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
"""
values = {}
for sysfile in self._written_sysfiles:
values[sysfile] = self.get_sysfile_value(sysfile)
for sysfile, binary in self._written_sysfiles:
values[sysfile] = self.get_sysfile_value(sysfile, binary=binary)
return values
def set_sysfile_values(self, params):
"""
The plural version of ``set_sysfile_value``. Takes a single parameter which is a mapping of
file paths to values to be set. By default, every value written will be verified. The can
be disabled for individual paths by appending ``'!'`` to them.
file paths to values to be set. By default, every value written will be verified. This can
be disabled for individual paths by appending ``'!'`` to them. To enable values being
written as binary data, a ``'^'`` can be prefixed to the path.
"""
for sysfile, value in params.iteritems():
verify = not sysfile.endswith('!')
sysfile = sysfile.rstrip('!')
self.set_sysfile_value(sysfile, value, verify=verify)
binary = sysfile.startswith('^')
sysfile = sysfile.lstrip('^')
self.set_sysfile_value(sysfile, value, verify=verify, binary=binary)
def deploy_busybox(self, context, force=False):
"""
@ -309,6 +349,29 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
please see: https://pythonhosted.org/wlauto/writing_extensions.html""")
def is_network_connected(self):
"""
Checks for internet connectivity on the device by pinging IP address provided.
:param ip_address: IP address to ping. Default is Google's public DNS server (8.8.8.8)
:returns: ``True`` if internet is available, ``False`` otherwise.
"""
self.logger.debug('Checking for internet connectivity...')
return self._ping_server(GOOGLE_DNS_SERVER_ADDRESS)
def _ping_server(self, ip_address, timeout=1, packet_count=1):
output = self.execute('ping -q -c {} -w {} {}'.format(packet_count, timeout, ip_address),
check_exit_code=False)
if 'network is unreachable' in output.lower():
self.logger.debug('Cannot find IP address {}'.format(ip_address))
return False
else:
self.logger.debug('Found IP address {}'.format(ip_address))
return True
def get_binary_path(self, name, search_system_binaries=True):
"""
Searches the devices ``binary_directory`` for the given binary,
@ -390,7 +453,7 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
signal_string = '-s {}'.format(signal) if signal else ''
self.execute('kill {} {}'.format(signal_string, pid), as_root=as_root)
def killall(self, process_name, signal=None, as_root=False): # pylint: disable=W0221
def killall(self, process_name, signal=None, as_root=None): # pylint: disable=W0221
"""
Kill all processes with the specified name.
@ -401,6 +464,8 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
Modified in version 2.1.5: added ``as_root`` parameter.
"""
if as_root is None:
as_root = self.is_rooted
for pid in self.get_pids_of(process_name):
self.kill(pid, signal=signal, as_root=as_root)
@ -412,20 +477,6 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
else:
raise ValueError(c)
def get_number_of_online_cpus(self, c):
return len(self.get_online_cpus(c))
def set_number_of_online_cpus(self, core, number):
core_ids = [i for i, c in enumerate(self.core_names) if c == core]
max_cores = len(core_ids)
if number > max_cores:
message = 'Attempting to set the number of active {} to {}; maximum is {}'
raise ValueError(message.format(core, number, max_cores))
for i in xrange(0, number):
self.enable_cpu(core_ids[i])
for i in xrange(number, max_cores):
self.disable_cpu(core_ids[i])
# hotplug
def enable_cpu(self, cpu):
@ -464,17 +515,17 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
sysfile = '/sys/devices/system/cpu/{}/online'.format(cpu)
self.set_sysfile_value(sysfile, status)
def get_number_of_active_cores(self, core):
def get_number_of_online_cores(self, core):
if core not in self.core_names:
raise ValueError('Unexpected core: {}; must be in {}'.format(core, list(set(self.core_names))))
active_cpus = self.active_cpus
online_cpus = self.online_cpus
num_active_cores = 0
for i, c in enumerate(self.core_names):
if c == core and i in active_cpus:
if c == core and i in online_cpus:
num_active_cores += 1
return num_active_cores
def set_number_of_active_cores(self, core, number): # NOQA
def set_number_of_online_cores(self, core, number): # NOQA
if core not in self.core_names:
raise ValueError('Unexpected core: {}; must be in {}'.format(core, list(set(self.core_names))))
core_ids = [i for i, c in enumerate(self.core_names) if c == core]
@ -487,8 +538,7 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
# make sure at least one other core is enabled to avoid trying to
# hotplug everything.
for i, c in enumerate(self.core_names):
if c != core:
self.enable_cpu(i)
if c != core and i in self.online_cpus:
break
else: # did not find one
raise ValueError('Cannot hotplug all cpus on the device!')
@ -540,7 +590,8 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
def get_device_model(self):
if self.file_exists("/proc/device-tree/model"):
raw_model = self.execute("cat /proc/device-tree/model")
return '_'.join(raw_model.split()[:2])
device_model_to_return = '_'.join(raw_model.split()[:2])
return device_model_to_return.rstrip(' \t\r\n\0')
# Right now we don't know any other way to get device model
# info in linux on arm platforms
return None
@ -549,7 +600,7 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
def _check_ready(self):
if not self._is_ready:
raise AttributeError('Device not ready.')
raise RuntimeError('Device not ready (has connect() been called?)')
def _get_core_cluster(self, core):
"""Returns the first cluster that has cores of the specified type. Raises
@ -583,17 +634,11 @@ class LinuxDevice(BaseLinuxDevice):
description='Optionally, telnet may be used instead of ssh, though this is discouraged.'),
Parameter('boot_timeout', kind=int, default=120,
description='How long to try to connect to the device after a reboot.'),
Parameter('working_directory', default=None,
description='''
Working directory to be used by WA. This must be in a location where the specified user
has write permissions. This will default to /home/<username>/wa (or to /root/wa, if
username is 'root').
'''),
]
@property
def is_rooted(self):
self._check_ready()
if self._is_rooted is None:
# First check if the user is root
try:
@ -632,7 +677,11 @@ class LinuxDevice(BaseLinuxDevice):
# Power control
def reset(self):
self.execute('reboot', as_root=True)
try:
self.execute('reboot', as_root=True)
except DeviceError as e:
if 'Connection dropped' not in e.message:
raise e
self._is_ready = False
def hard_reset(self):
@ -644,8 +693,15 @@ class LinuxDevice(BaseLinuxDevice):
else:
self.reset()
self.logger.debug('Waiting for device...')
# Wait a fixed delay before starting polling to give the device time to
# shut down, otherwise, might create the connection while it's still shutting
# down resulting in subsequenct connection failing.
initial_delay = 20
time.sleep(initial_delay)
boot_timeout = max(self.boot_timeout - initial_delay, 10)
start_time = time.time()
while (time.time() - start_time) < self.boot_timeout:
while (time.time() - start_time) < boot_timeout:
try:
s = socket.create_connection((self.host, self.port), timeout=5)
s.close()
@ -669,15 +725,6 @@ class LinuxDevice(BaseLinuxDevice):
# Execution
def has_root(self):
try:
self.execute('ls /', as_root=True)
return True
except DeviceError as e:
if 'not in the sudoers file' not in e.message:
raise e
return False
def execute(self, command, timeout=default_timeout, check_exit_code=True, background=False,
as_root=False, strip_colors=True, **kwargs):
"""
@ -720,13 +767,15 @@ class LinuxDevice(BaseLinuxDevice):
except CalledProcessError as e:
raise DeviceError(e)
def kick_off(self, command, as_root=False):
def kick_off(self, command, as_root=None):
"""
Like execute but closes adb session and returns immediately, leaving the command running on the
device (this is different from execute(background=True) which keeps adb connection open and returns
Like execute but closes ssh session and returns immediately, leaving the command running on the
device (this is different from execute(background=True) which keeps ssh connection open and returns
a subprocess object).
"""
if as_root is None:
as_root = self.is_rooted
self._check_ready()
command = 'sh -c "{}" 1>/dev/null 2>/dev/null &'.format(escape_double_quotes(command))
return self.shell.execute(command, as_root=as_root)

@ -0,0 +1,165 @@
# Copyright 2017 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.
#
import os
from math import ceil
from wlauto.core.extension import Parameter
from wlauto.core.workload import Workload
from wlauto.core.resource import NO_ONE
from wlauto.common.resources import Executable
from wlauto.common.android.resources import ReventFile
from wlauto.exceptions import WorkloadError
from wlauto.utils.revent import ReventRecording
class ReventWorkload(Workload):
# pylint: disable=attribute-defined-outside-init
description = """
A workload for playing back revent recordings. You can supply three
different files:
1. {device_model}.setup.revent
2. {device_model}.run.revent
3. {device_model}.teardown.revent
You may generate these files using the wa record command using the -s flag
to specify the stage (``setup``, ``run``, ``teardown``)
You may also supply an 'idle_time' in seconds in place of the run file.
The ``run`` file may only be omitted if you choose to run this way, but
while running idle may supply ``setup`` and ``teardown`` files.
To use a ``setup`` or ``teardown`` file set the setup_required and/or
teardown_required class attributes to True (default: False).
N.B. This is the default description. You may overwrite this for your
workload to include more specific information.
"""
setup_required = False
teardown_required = False
parameters = [
Parameter(
'idle_time', kind=int, default=None,
description='''
The time you wish the device to remain idle for (if a value is
given then this overrides any .run revent file).
'''),
]
def __init__(self, device, _call_super=True, **kwargs):
if _call_super:
Workload.__init__(self, device, **kwargs)
self.setup_timeout = kwargs.get('setup_timeout', None)
self.run_timeout = kwargs.get('run_timeout', None)
self.teardown_timeout = kwargs.get('teardown_timeout', None)
self.revent_setup_file = None
self.revent_run_file = None
self.revent_teardown_file = None
self.on_device_setup_revent = None
self.on_device_run_revent = None
self.on_device_teardown_revent = None
self.statedefs_dir = None
def initialize(self, context):
devpath = self.device.path
self.on_device_revent_binary = devpath.join(self.device.binaries_directory, 'revent')
def setup(self, context):
devpath = self.device.path
if self.setup_required:
self.revent_setup_file = context.resolver.get(ReventFile(self, 'setup'))
if self.revent_setup_file:
self.on_device_setup_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_setup_file)[-1])
duration = ReventRecording(self.revent_setup_file).duration
self.default_setup_timeout = ceil(duration) + 30
if not self.idle_time:
self.revent_run_file = context.resolver.get(ReventFile(self, 'run'))
if self.revent_run_file:
self.on_device_run_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_run_file)[-1])
self.default_run_timeout = ceil(ReventRecording(self.revent_run_file).duration) + 30
if self.teardown_required:
self.revent_teardown_file = context.resolver.get(ReventFile(self, 'teardown'))
if self.revent_teardown_file:
self.on_device_teardown_revent = devpath.join(self.device.working_directory,
os.path.split(self.revent_teardown_file)[-1])
duration = ReventRecording(self.revent_teardown_file).duration
self.default_teardown_timeout = ceil(duration) + 30
self._check_revent_files(context)
Workload.setup(self, context)
if self.revent_setup_file is not None:
self.setup_timeout = self.setup_timeout or self.default_setup_timeout
self.device.killall('revent')
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_setup_revent)
self.device.execute(command, timeout=self.setup_timeout)
self.logger.debug('Revent setup completed.')
def run(self, context):
if not self.idle_time:
self.run_timeout = self.run_timeout or self.default_run_timeout
command = '{} replay {}'.format(self.on_device_revent_binary, self.on_device_run_revent)
self.logger.debug('Replaying {}'.format(os.path.basename(self.on_device_run_revent)))
self.device.execute(command, timeout=self.run_timeout)
self.logger.debug('Replay completed.')
else:
self.logger.info('Idling for ' + str(self.idle_time) + ' seconds.')
self.device.sleep(self.idle_time)
self.logger.info('Successfully did nothing for ' + str(self.idle_time) + ' seconds!')
def update_result(self, context):
pass
def teardown(self, context):
if self.revent_teardown_file is not None:
self.teardown_timeout = self.teardown_timeout or self.default_teardown_timeout
command = '{} replay {}'.format(self.on_device_revent_binary,
self.on_device_teardown_revent)
self.device.execute(command, timeout=self.teardown_timeout)
self.logger.debug('Replay completed.')
self.device.killall('revent')
if self.revent_setup_file is not None:
self.device.delete_file(self.on_device_setup_revent)
if not self.idle_time:
self.device.delete_file(self.on_device_run_revent)
if self.revent_teardown_file is not None:
self.device.delete_file(self.on_device_teardown_revent)
def _check_revent_files(self, context):
# check the revent binary
revent_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
if not os.path.isfile(revent_binary):
message = '{} does not exist. '.format(revent_binary)
message += 'Please build revent for your system and place it in that location'
raise WorkloadError(message)
if not self.revent_run_file and not self.idle_time:
# pylint: disable=too-few-format-args
message = 'It seems a {0}.run.revent file does not exist, '\
'Please provide one for your device: {0}.'
raise WorkloadError(message.format(self.device.name))
self.on_device_revent_binary = self.device.install_executable(revent_binary)
if self.revent_setup_file is not None:
self.device.push_file(self.revent_setup_file, self.on_device_setup_revent)
if not self.idle_time:
self.device.push_file(self.revent_run_file, self.on_device_run_revent)
if self.revent_teardown_file is not None:
self.device.push_file(self.revent_teardown_file, self.on_device_teardown_revent)

@ -54,11 +54,15 @@ retry_on_status = ['FAILED', 'PARTIAL']
# How many times a job will be re-run before giving up
max_retries = 3
# If WA should delete its files from the device after the run is completed
clean_up = False
####################################################################################################
######################################### Device Settings ##########################################
####################################################################################################
# Specify the device you want to run workload automation on. This must be a #
# string with the ID of the device. At the moment, only 'TC2' is supported. #
# string with the ID of the device. Common options are 'generic_android' and #
# 'generic_linux'. Run ``wa list devices`` to see all available options. #
# #
device = 'generic_android'
@ -84,7 +88,7 @@ device_config = dict(
####################################################################################################
################################### Instrumention Configuration ####################################
################################### Instrumentation Configuration ####################################
####################################################################################################
# This defines the additionnal instrumentation that will be enabled during workload execution, #
# which in turn determines what additional data (such as /proc/interrupts content or Streamline #
@ -189,7 +193,7 @@ logging = {
####################################################################################################
#################################### Instruments Configuration #####################################
####################################################################################################
# Instrumention Configuration is related to specific insturment's settings. Some of the #
# Instrumentation Configuration is related to specific instrument's settings. Some of the #
# instrumentations require specific settings in order for them to work. These settings are #
# specified here. #
# Note that these settings only take effect if the corresponding instrument is
@ -222,10 +226,10 @@ logging = {
####################################################################################################
######################################### DAQ configuration ########################################
# The host address of the machine that runs the daq Server which the insturment communicates with
# The host address of the machine that runs the daq Server which the instrument communicates with
#daq_server_host = '10.1.17.56'
# The port number for daq Server in which daq insturment communicates with
# The port number for daq Server in which daq instrument communicates with
#daq_server_port = 56788
# The values of resistors 1 and 2 (in Ohms) across which the voltages are measured

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -114,8 +114,8 @@ class ConfigLoader(object):
new_config = load_struct_from_yaml(source)
else:
raise ConfigError('Unknown config format: {}'.format(source))
except LoadSyntaxError as e:
raise ConfigError(e)
except (LoadSyntaxError, ValueError) as e:
raise ConfigError('Invalid config "{}":\n\t{}'.format(source, e))
self._config = merge_dicts(self._config, new_config,
list_duplicates='first',
@ -152,7 +152,8 @@ def init_environment(env_root, dep_dir, extension_paths, overwrite_existing=Fals
os.makedirs(env_root)
with open(os.path.join(_this_dir, '..', 'config_example.py')) as rf:
text = re.sub(r'""".*?"""', '', rf.read(), 1, re.DOTALL)
with open(os.path.join(_env_root, 'config.py'), 'w') as wf:
config_path = os.path.join(env_root, 'config.py')
with open(config_path, 'w') as wf:
wf.write(text)
os.makedirs(dep_dir)
@ -173,9 +174,11 @@ def init_environment(env_root, dep_dir, extension_paths, overwrite_existing=Fals
os.chown(os.path.join(root, d), uid, gid)
for f in files: # pylint: disable=W0621
os.chown(os.path.join(root, f), uid, gid)
return config_path
_env_root = os.getenv('WA_USER_DIRECTORY', os.path.join(_user_home, '.workload_automation'))
_env_root = os.path.abspath(_env_root)
_dep_dir = os.path.join(_env_root, 'dependencies')
_extension_paths = [os.path.join(_env_root, ext.default_path) for ext in _extensions]
_env_var_paths = os.getenv('WA_EXTENSION_PATHS', '')
@ -189,7 +192,8 @@ for filename in ['config.py', 'config.yaml']:
_env_configs.append(filepath)
if not os.path.isdir(_env_root):
init_environment(_env_root, _dep_dir, _extension_paths)
cfg_path = init_environment(_env_root, _dep_dir, _extension_paths)
_env_configs.append(cfg_path)
elif not _env_configs:
filepath = os.path.join(_env_root, 'config.py')
with open(os.path.join(_this_dir, '..', 'config_example.py')) as f:
@ -211,4 +215,3 @@ if os.path.isfile(_packages_file):
for config in _env_configs:
settings.update(config)

@ -481,6 +481,7 @@ class RunConfiguration(object):
RunConfigurationItem('flashing_config', 'dict', 'replace'),
RunConfigurationItem('retry_on_status', 'list', 'replace'),
RunConfigurationItem('max_retries', 'scalar', 'replace'),
RunConfigurationItem('clean_up', 'scalar', 'replace'),
]
# Configuration specified for each workload spec. "workload_parameters"
@ -757,7 +758,7 @@ class RunConfiguration(object):
if spec.match_selectors(selectors):
instrumentation_config = self._raw_config['instrumentation']
for instname in spec.instrumentation:
if instname not in instrumentation_config:
if instname not in instrumentation_config and not instname.startswith('~'):
instrumentation_config.append(instname)
self.workload_specs.append(spec)

@ -381,7 +381,20 @@ class Device(Extension):
"""
raise NotImplementedError()
def set_sysfile_value(self, filepath, value, verify=True):
def sleep(self, seconds):
"""Sleep for the specified time on the target device.
:param seconds: Time in seconds to sleep on the device
The sleep is executed on the device using self.execute(). We
set the timeout for this command to be 10 seconds longer than
the sleep itself to make sure the command has time to complete
before we timeout.
"""
self.execute("sleep {}".format(seconds), timeout=seconds + 10)
def set_sysfile_value(self, filepath, value, verify=True, binary=False):
"""
Write the specified value to the specified file on the device
and verify that the value has actually been written.
@ -390,13 +403,14 @@ class Device(Extension):
:param value: The value to be written to the file. Must be
an int or a string convertable to an int.
:param verify: Specifies whether the value should be verified, once written.
:param binary: Specifies whether the value should be written as binary data.
Should raise DeviceError if could write value.
"""
raise NotImplementedError()
def get_sysfile_value(self, sysfile, kind=None):
def get_sysfile_value(self, sysfile, kind=None, binary=False):
"""
Get the contents of the specified sysfile.
@ -406,6 +420,8 @@ class Device(Extension):
be any Python callable that takes a single str argument.
If not specified or is None, the contents will be returned
as a string.
:param binary: Whether the value should be encoded into base64 for reading
to deal with binary format.
"""
raise NotImplementedError()
@ -426,6 +442,13 @@ class Device(Extension):
"""
pass
def is_network_connected(self):
"""
Checks if the device is connected to the internet
"""
raise NotImplementedError()
def __str__(self):
return 'Device<{}>'.format(self.name)

@ -14,10 +14,12 @@
#
from __future__ import absolute_import
import sys
import argparse
import logging
import os
import signal
import subprocess
import warnings
@ -41,6 +43,9 @@ def load_commands(subparsers):
for command in ext_loader.list_commands():
settings.commands[command.name] = ext_loader.get_command(command.name, subparsers=subparsers)
def convert_TERM_into_INT_handler(signal, frame):
logger.critical("TERM received, aborting")
raise KeyboardInterrupt()
def main():
try:
@ -62,6 +67,7 @@ def main():
settings.update(args.config)
init_logging(settings.verbosity)
signal.signal(signal.SIGTERM, convert_TERM_into_INT_handler)
command = settings.commands[args.command]
sys.exit(command.execute(args))

@ -56,7 +56,8 @@ from wlauto.core.extension_loader import ExtensionLoader
from wlauto.core.resolver import ResourceResolver
from wlauto.core.result import ResultManager, IterationResult, RunResult
from wlauto.exceptions import (WAError, ConfigError, TimeoutError, InstrumentError,
DeviceError, DeviceNotRespondingError)
DeviceError, DeviceNotRespondingError, ResourceError,
HostError)
from wlauto.utils.misc import ensure_directory_exists as _d, get_traceback, merge_dicts, format_duration
@ -204,6 +205,9 @@ class ExecutionContext(object):
def add_metric(self, *args, **kwargs):
self.result.add_metric(*args, **kwargs)
def add_classifiers(self, **kwargs):
self.result.classifiers.update(kwargs)
def add_artifact(self, name, path, kind, *args, **kwargs):
if self.current_job is None:
self.add_run_artifact(name, path, kind, *args, **kwargs)
@ -341,6 +345,11 @@ class Executor(object):
runner = self._get_runner(result_manager)
runner.init_queue(self.config.workload_specs)
runner.run()
if getattr(self.config, "clean_up", False):
self.logger.info('Clearing WA files from device')
self.device.delete_file(self.device.binaries_directory)
self.device.delete_file(self.device.working_directory)
self.execute_postamble()
def execute_postamble(self):
@ -633,7 +642,7 @@ class Runner(object):
job.iteration = self.context.current_iteration
if job.result.status in self.config.retry_on_status:
if job.retry >= self.config.max_retries:
self.logger.error('Exceeded maxium number of retries. Abandoning job.')
self.logger.error('Exceeded maximum number of retries. Abandoning job.')
else:
self.logger.info('Job status was {}. Retrying...'.format(job.result.status))
retry_job = RunnerJob(job.spec, job.retry + 1)
@ -728,6 +737,13 @@ class Runner(object):
filepath = os.path.join(settings.output_directory, filename)
self.device.capture_screen(filepath)
def _take_uiautomator_dump(self, filename):
if self.context.output_directory:
filepath = os.path.join(self.context.output_directory, filename)
else:
filepath = os.path.join(settings.output_directory, filename)
self.device.capture_ui_hierarchy(filepath)
@contextmanager
def _handle_errors(self, action, on_error_status=IterationResult.FAILED):
try:
@ -741,15 +757,21 @@ class Runner(object):
if self.current_job:
self.current_job.result.status = on_error_status
self.current_job.result.add_event(str(we))
try:
self._take_screenshot('error.png')
except Exception, e: # pylint: disable=W0703
# We're already in error state, so the fact that taking a
# screenshot failed is not surprising...
pass
# There is no point in taking a screenshot ect if the issue is not
# with the device but with the host or a missing resource
if not (isinstance(we, ResourceError) or isinstance(we, HostError)):
try:
self._take_screenshot('error.png')
if self.device.platform == 'android':
self._take_uiautomator_dump('error.uix')
except Exception, e: # pylint: disable=W0703
# We're already in error state, so the fact that taking a
# screenshot failed is not surprising...
pass
if action:
action = action[0].lower() + action[1:]
self.logger.error('Error while {}:\n\t{}'.format(action, we))
self.logger.error('Error while {}:\n\t{}'.format(action, str(we).replace("\n", "\n\t")))
except Exception, e: # pylint: disable=W0703
error_text = '{}("{}")'.format(e.__class__.__name__, e)
if self.current_job:

@ -224,18 +224,11 @@ class Param(object):
else:
new_value = current_value + [value]
setattr(obj, self.name, new_value)
def validate(self, obj):
value = getattr(obj, self.name, None)
if value is not None:
if self.allowed_values:
self._validate_allowed_values(obj, value)
if self.constraint:
self._validate_constraint(obj, value)
else:
if self.mandatory:
msg = 'No value specified for mandatory parameter {} in {}.'
raise ConfigError(msg.format(self.name, obj.name))
def get_type_name(self):
typename = str(self.kind)
@ -567,7 +560,9 @@ class Extension(object):
if self.name is None:
raise ValidationError('Name not set for {}'.format(self._classname))
for param in self.parameters:
param.validate(self)
if param.mandatory and getattr(self, param.name, None) is None:
msg = 'No value specified for mandatory parameter {} in {}.'
raise ConfigError(msg.format(param.name, self.name))
def initialize(self, context):
pass

@ -32,4 +32,3 @@ def get_extension_type(ext):
if isinstance(ext, cls):
return name
raise ValueError('Unknown extension type: {}'.format(ext.__class__.__name__))

@ -241,7 +241,7 @@ class ManagedCallback(object):
except (KeyboardInterrupt, DeviceNotRespondingError, TimeoutError): # pylint: disable=W0703
raise
except Exception as e: # pylint: disable=W0703
logger.error('Error in insturment {}'.format(self.instrument.name))
logger.error('Error in instrument {}'.format(self.instrument.name))
global failures_detected # pylint: disable=W0603
failures_detected = True
if isinstance(e, WAError):
@ -396,4 +396,3 @@ class Instrument(Extension):
def __repr__(self):
return 'Instrument({})'.format(self.name)

@ -69,7 +69,11 @@ class ResourceResolver(object):
self.logger.debug('\t{}'.format(result))
return result
if strict:
raise ResourceError('{} could not be found'.format(resource))
if kwargs:
criteria = ', '.join(['{}:{}'.format(k, v) for k, v in kwargs.iteritems()])
raise ResourceError('{} ({}) could not be found'.format(resource, criteria))
else:
raise ResourceError('{} could not be found'.format(resource))
self.logger.debug('Resource {} not found.'.format(resource))
return None

@ -38,8 +38,8 @@ class GetterPriority(object):
"""
cached = 20
preferred = 10
remote = 5
environment = 0
remote = -4
external_package = -5
package = -10

@ -327,4 +327,3 @@ class Metric(object):
return '<{}>'.format(result)
__repr__ = __str__

@ -186,4 +186,3 @@ def send(signal, sender, *args, **kwargs):
"""
dispatcher.send(signal, sender, *args, **kwargs)

@ -18,7 +18,7 @@ from collections import namedtuple
VersionTuple = namedtuple('Version', ['major', 'minor', 'revision'])
version = VersionTuple(2, 4, 0)
version = VersionTuple(2, 7, 0)
def get_wa_version():

@ -37,6 +37,7 @@ class Workload(Extension):
supported_devices = []
supported_platforms = []
summary_metrics = []
requires_network = False
def __init__(self, device, **kwargs):
"""
@ -69,7 +70,7 @@ class Workload(Extension):
"""
pass
def setup(self, context):
def setup(self, context): # pylint: disable=unused-argument
"""
Perform the setup necessary to run the workload, such as copying the necessary files
to the device, configuring the environments, etc.
@ -78,7 +79,8 @@ class Workload(Extension):
the workload.
"""
pass
if self.requires_network:
self.check_network_connected()
def run(self, context):
"""Execute the workload. This is the method that performs the actual "work" of the"""
@ -99,6 +101,10 @@ class Workload(Extension):
def finalize(self, context):
pass
def check_network_connected(self):
if not self.device.is_network_connected():
message = 'Workload "{}" requires internet. Device "{}" does not appear to be connected to the internet.'
raise WorkloadError(message.format(self.name, self.device.name))
def __str__(self):
return '<Workload {}>'.format(self.name)

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -199,16 +199,6 @@ class Gem5AndroidDevice(BaseGem5Device, AndroidDevice):
props = self._get_android_properties(context)
return props
def disable_screen_lock(self):
"""
Attempts to disable he screen lock on the device.
Overridden here as otherwise we have issues with too many backslashes.
"""
lockdb = '/data/system/locksettings.db'
sqlcommand = "update locksettings set value=\'0\' where name=\'screenlock.disabled\';"
self.execute('sqlite3 {} "{}"'.format(lockdb, sqlcommand), as_root=True)
def capture_screen(self, filepath):
if BaseGem5Device.capture_screen(self, filepath):
return

@ -81,9 +81,7 @@ class Juno(BigLittleDevice):
'fdt_support': True,
}
),
Parameter('bootargs', default='console=ttyAMA0,115200 earlyprintk=pl011,0x7ff80000 '
'verbose debug init=/init root=/dev/sda1 rw ip=dhcp '
'rootwait video=DVI-D-1:1920x1080R@60',
Parameter('bootargs',
description='''Default boot arguments to use when boot_arguments were not.'''),
]
@ -158,7 +156,7 @@ class Juno(BigLittleDevice):
target.sendline('ip addr list eth0')
time.sleep(1)
try:
target.expect('inet ([1-9]\d*.\d+.\d+.\d+)', timeout=10)
target.expect(r'inet ([1-9]\d*.\d+.\d+.\d+)', timeout=10)
self.adb_name = target.match.group(1) + ':5555' # pylint: disable=W0201
break
except pexpect.TIMEOUT:
@ -220,4 +218,3 @@ class Juno(BigLittleDevice):
def get_android_id(self):
# Android ID currenlty not set properly in Juno Android builds.
return 'abad1deadeadbeef'

@ -0,0 +1,14 @@
from wlauto import AndroidDevice
class MeizuMX6(AndroidDevice):
name = 'meizumx6'
@property
def is_rooted(self):
# "su" executable on a rooted Meizu MX6 is targeted
# specifically towards Android application and cannot
# be used to execute a command line shell. This makes it
# "broken" from WA prespective.
return False

@ -35,4 +35,3 @@ class OdroidXU3(AndroidDevice):
description='Serial port on which the device is connected'),
Parameter('baudrate', default=115200, kind=int, description='Serial connection baud rate'),
]

@ -847,4 +847,3 @@ def _slow_sendline(target, line):
target.send(c)
time.sleep(0.1)
target.sendline('')

@ -33,4 +33,3 @@ class Xe503c12Chormebook(LinuxDevice):
]
abi = 'armeabi'

@ -12,5 +12,3 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

@ -97,4 +97,3 @@ class ChromeOsDevice(LinuxDevice):
else:
pass
self.ui_status = None

@ -32,4 +32,3 @@ class OdroidXU3LinuxDevice(LinuxDevice):
]
abi = 'armeabi'

@ -55,4 +55,3 @@ logObserver.start()
def start_logging(level, fmt='%(asctime)s %(levelname)-8s: %(message)s'):
logging.basicConfig(level=getattr(logging, level), format=fmt)

@ -1,7 +1,12 @@
# CROSS_COMPILE=aarch64-linux-gnu- make
#
CC=gcc
CFLAGS=-static -lc
ifdef DEBUG
CFLAGS=-static -lc -g
else
CFLAGS=-static -lc -O2
endif
revent: revent.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) revent.c -o revent

File diff suppressed because it is too large Load Diff

11
wlauto/external/sqlite/README vendored Normal file

@ -0,0 +1,11 @@
For WA we use a slightly modified version of sqlite3 so that it can
be built statically. We used the amalgamated sqlite3 version 3.12.2.
which is under the public domain.
https://www.sqlite.org/download.html
Build command:
gcc shell.c sqlite3.c -lpthread -ldl -static -O2 -fPIC -DPIC -DSQLITE_OMIT_LOAD_EXTENSION
You will need to apply the diff in static.patch

20
wlauto/external/sqlite/static.patch vendored Normal file

@ -0,0 +1,20 @@
--- shell.c 2016-05-09 15:35:26.952309563 +0100
+++ shell.c.bak 2016-05-09 15:33:41.991259588 +0100
@@ -4503,7 +4503,7 @@
static char *home_dir = NULL;
if( home_dir ) return home_dir;
+/*#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
-#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
&& !defined(__RTP__) && !defined(_WRS_KERNEL)
{
struct passwd *pwent;
@@ -4512,7 +4512,7 @@
home_dir = pwent->pw_dir;
}
}
+#endif*/
-#endif
#if defined(_WIN32_WCE)
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()

18
wlauto/external/uiauto/app/build.gradle vendored Normal file

@ -0,0 +1,18 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
defaultConfig {
minSdkVersion 18
targetSdkVersion 25
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
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'
}

@ -0,0 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arm.wlauto.uiauto">
<uses-permission android:name="android.permission.READ_LOGS"/>
<application>
<uses-library android:name="android.test.runner"/>
</application>
</manifest>

@ -0,0 +1,58 @@
/* Copyright 2013-2016 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.wlauto.uiauto;
import android.os.Bundle;
import android.support.test.uiautomator.UiObject;
// Import the uiautomator libraries
/**
* ApplaunchInterface.java
* Interface used for enabling uxperfapplaunch workload.
* This interface gets implemented by all workloads that support application launch
* instrumentation.
*/
public interface ApplaunchInterface {
/**
* Sets the launchEndObject of a workload, which is a UiObject that marks
* the end of the application launch.
*/
public UiObject getLaunchEndObject();
/**
* Runs the Uiautomation methods for clearing the initial run
* dialogues on the first time installation of an application package.
*/
public void runApplicationInitialization() throws Exception;
/**
* Provides the application launch command of the application which is
* constructed as a string from the workload.
*/
public String getLaunchCommand();
/** Passes the workload parameters. */
public void setWorkloadParameters(Bundle parameters);
/** Initialize the instrumentation for the workload */
public void initialize_instrumentation();
}

@ -0,0 +1,728 @@
/* Copyright 2013-2016 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.wlauto.uiauto;
import android.app.Instrumentation;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiSelector;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiWatcher;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static android.support.test.InstrumentationRegistry.getArguments;
public class BaseUiAutomation {
// Time in milliseconds
public long uiAutoTimeout = 4000;
public enum ScreenOrientation { RIGHT, NATURAL, LEFT };
public enum Direction { UP, DOWN, LEFT, RIGHT, NULL };
public enum PinchType { IN, OUT, NULL };
public static final int CLICK_REPEAT_INTERVAL_MINIMUM = 5;
public static final int CLICK_REPEAT_INTERVAL_DEFAULT = 50;
public Bundle parameters;
public Instrumentation mInstrumentation;
public Context mContext;
public UiDevice mDevice;
public void initialize_instrumentation(){
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(mInstrumentation);
mContext = mInstrumentation.getTargetContext();
}
/*
* Used by clickUiObject() methods in order to provide a consistent API
*/
public enum FindByCriteria { BY_ID, BY_TEXT, BY_DESC; }
/**
* Basic marker API for workloads to generate start and end markers for
* deliminating and timing actions. Markers are output to logcat with debug
* priority. Actions represent a series of UI interactions to time.
*
* The marker API provides a way for instruments and result processors to hook into
* per-action timings by parsing logcat logs produced per workload iteration.
*
* The marker output consists of a logcat tag 'UX_PERF' and a message. The
* message consists of a name for the action and a timestamp. The timestamp
* is separated by a single space from the name of the action.
*
* Typical usage:
*
* ActionLogger logger = ActionLogger("testTag", parameters);
* logger.start();
* // actions to be recorded
* logger.stop();
*/
public class ActionLogger {
private String testTag;
private boolean enabled;
public ActionLogger(String testTag, Bundle parameters) {
this.testTag = testTag;
this.enabled = parameters.getBoolean("markers_enabled");
}
public void start() {
if (enabled) {
Log.d("UX_PERF", testTag + "_start " + System.nanoTime());
}
}
public void stop() throws Exception {
if (enabled) {
Log.d("UX_PERF", testTag + "_end " + System.nanoTime());
}
}
}
public void sleep(int second) {
SystemClock.sleep(second * 1000);
}
public boolean takeScreenshot(String name) {
Bundle params = getParams();
String pngDir = params.getString("workdir");
try {
return mDevice.takeScreenshot(new File(pngDir, name + ".png"));
} catch (NoSuchMethodError e) {
return true;
}
}
public void waitText(String text) throws UiObjectNotFoundException {
waitText(text, 600);
}
public void waitText(String text, int second) throws UiObjectNotFoundException {
UiSelector selector = new UiSelector();
UiObject textObj = mDevice.findObject(selector.text(text)
.className("android.widget.TextView"));
waitObject(textObj, second);
}
public void waitObject(UiObject obj) throws UiObjectNotFoundException {
waitObject(obj, 600);
}
public void waitObject(UiObject obj, int second) throws UiObjectNotFoundException {
if (!obj.waitForExists(second * 1000)) {
throw new UiObjectNotFoundException("UiObject is not found: "
+ obj.getSelector().toString());
}
}
public boolean waitUntilNoObject(UiObject obj, int second) {
return obj.waitUntilGone(second * 1000);
}
public void clearLogcat() throws Exception {
Runtime.getRuntime().exec("logcat -c");
}
public void waitForLogcatText(String searchText, long timeout) throws Exception {
long startTime = System.currentTimeMillis();
Process process = Runtime.getRuntime().exec("logcat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
long currentTime = System.currentTimeMillis();
boolean found = false;
while ((currentTime - startTime) < timeout) {
sleep(2); // poll every two seconds
while ((line = reader.readLine()) != null) {
if (line.contains(searchText)) {
found = true;
break;
}
}
if (found) {
break;
}
currentTime = System.currentTimeMillis();
}
process.destroy();
if ((currentTime - startTime) >= timeout) {
throw new TimeoutException(String.format("Timed out waiting for Logcat text \"%s\"",
searchText));
}
}
public Integer[] splitVersion(String versionString) {
String pattern = "(\\d+).(\\d+).(\\d+)";
Pattern r = Pattern.compile(pattern);
ArrayList<Integer> result = new ArrayList<Integer>();
Matcher m = r.matcher(versionString);
if (m.find() && m.groupCount() > 0) {
for(int i=1; i<=m.groupCount(); i++) {
result.add(Integer.parseInt(m.group(i)));
}
} else {
throw new IllegalArgumentException(versionString + " - unknown format");
}
return result.toArray(new Integer[result.size()]);
}
//Return values:
// -1 = a lower than b
// 0 = a and b equal
// 1 = a greater than b
public int compareVersions(Integer[] a, Integer[] b) {
if (a.length != b.length) {
String msg = "Versions do not match format:\n %1$s\n %1$s";
msg = String.format(msg, Arrays.toString(a), Arrays.toString(b));
throw new IllegalArgumentException(msg);
}
for(int i=0; i<a.length; i++) {
if(a[i] > b[i])
return 1;
else if(a[i] < b[i])
return -1;
}
return 0;
}
public void registerWatcher(String name, UiWatcher watcher) {
mDevice.registerWatcher(name, watcher);
}
public void runWatchers() {
mDevice.runWatchers();
}
public void removeWatcher(String name) {
mDevice.removeWatcher(name);
}
public void pressEnter() {
mDevice.pressEnter();
}
public void pressHome() {
mDevice.pressHome();
}
public void pressBack() {
mDevice.pressBack();
}
public void pressDPadUp() {
mDevice.pressDPadUp();
}
public void pressDPadDown() {
mDevice.pressDPadDown();
}
public void pressDPadLeft() {
mDevice.pressDPadLeft();
}
public void pressDPadRight() {
mDevice.pressDPadRight();
}
public int getDisplayHeight() {
return mDevice.getDisplayHeight();
}
public int getDisplayWidth() {
return mDevice.getDisplayWidth();
}
public int getDisplayCentreWidth() {
return getDisplayWidth() / 2;
}
public int getDisplayCentreHeight() {
return getDisplayHeight() / 2;
}
public void tapDisplayCentre() {
tapDisplay(getDisplayCentreWidth(), getDisplayCentreHeight());
}
public void tapDisplay(int x, int y) {
mDevice.click(x, y);
}
public void uiDeviceSwipeUp(int steps) {
mDevice.swipe(
getDisplayCentreWidth(),
(getDisplayCentreHeight() + (getDisplayCentreHeight() / 2)),
getDisplayCentreWidth(),
(getDisplayCentreHeight() / 2),
steps);
}
public void uiDeviceSwipeDown(int steps) {
mDevice.swipe(
getDisplayCentreWidth(),
(getDisplayCentreHeight() / 2),
getDisplayCentreWidth(),
(getDisplayCentreHeight() + (getDisplayCentreHeight() / 2)),
steps);
}
public void uiDeviceSwipeLeft(int steps) {
mDevice.swipe(
(getDisplayCentreWidth() + (getDisplayCentreWidth() / 2)),
getDisplayCentreHeight(),
(getDisplayCentreWidth() / 2),
getDisplayCentreHeight(),
steps);
}
public void uiDeviceSwipeRight(int steps) {
mDevice.swipe(
(getDisplayCentreWidth() / 2),
getDisplayCentreHeight(),
(getDisplayCentreWidth() + (getDisplayCentreWidth() / 2)),
getDisplayCentreHeight(),
steps);
}
public void uiDeviceSwipe(Direction direction, int steps) throws Exception {
switch (direction) {
case UP:
uiDeviceSwipeUp(steps);
break;
case DOWN:
uiDeviceSwipeDown(steps);
break;
case LEFT:
uiDeviceSwipeLeft(steps);
break;
case RIGHT:
uiDeviceSwipeRight(steps);
break;
case NULL:
throw new Exception("No direction specified");
default:
break;
}
}
public void uiObjectSwipe(UiObject view, Direction direction, int steps) throws Exception {
switch (direction) {
case UP:
view.swipeUp(steps);
break;
case DOWN:
view.swipeDown(steps);
break;
case LEFT:
view.swipeLeft(steps);
break;
case RIGHT:
view.swipeRight(steps);
break;
case NULL:
throw new Exception("No direction specified");
default:
break;
}
}
public void uiObjectVertPinchIn(UiObject view, int steps, int percent) throws Exception {
final int FINGER_TOUCH_HALF_WIDTH = 20;
// Make value between 1 and 100
int nPercent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
float percentage = nPercent / 100f;
Rect rect = view.getVisibleBounds();
if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) {
throw new IllegalStateException("Object width is too small for operation");
}
// Start at the top-center and bottom-center of the control
Point startPoint1 = new Point(rect.centerX(), rect.centerY()
+ (int) ((rect.height() / 2) * percentage));
Point startPoint2 = new Point(rect.centerX(), rect.centerY()
- (int) ((rect.height() / 2) * percentage));
// End at the same point at the center of the control
Point endPoint1 = new Point(rect.centerX(), rect.centerY() + FINGER_TOUCH_HALF_WIDTH);
Point endPoint2 = new Point(rect.centerX(), rect.centerY() - FINGER_TOUCH_HALF_WIDTH);
view.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
}
public void uiObjectVertPinchOut(UiObject view, int steps, int percent) throws Exception {
final int FINGER_TOUCH_HALF_WIDTH = 20;
// Make value between 1 and 100
int nPercent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
float percentage = nPercent / 100f;
Rect rect = view.getVisibleBounds();
if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) {
throw new IllegalStateException("Object width is too small for operation");
}
// Start from the same point at the center of the control
Point startPoint1 = new Point(rect.centerX(), rect.centerY() + FINGER_TOUCH_HALF_WIDTH);
Point startPoint2 = new Point(rect.centerX(), rect.centerY() - FINGER_TOUCH_HALF_WIDTH);
// End at the top-center and bottom-center of the control
Point endPoint1 = new Point(rect.centerX(), rect.centerY()
+ (int) ((rect.height() / 2) * percentage));
Point endPoint2 = new Point(rect.centerX(), rect.centerY()
- (int) ((rect.height() / 2) * percentage));
view.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
}
public void setScreenOrientation(ScreenOrientation orientation) throws Exception {
switch (orientation) {
case RIGHT:
mDevice.setOrientationRight();
break;
case NATURAL:
mDevice.setOrientationNatural();
break;
case LEFT:
mDevice.setOrientationLeft();
break;
default:
throw new Exception("No orientation specified");
}
}
public void unsetScreenOrientation() throws Exception {
mDevice.unfreezeRotation();
}
public void uiObjectPerformLongClick(UiObject view, int steps) throws Exception {
Rect rect = view.getBounds();
mDevice.swipe(rect.centerX(), rect.centerY(),
rect.centerX(), rect.centerY(), steps);
}
public void uiDeviceSwipeVertical(int startY, int endY, int xCoordinate, int steps) {
mDevice.swipe(startY, xCoordinate, endY, xCoordinate, steps);
}
public void uiDeviceSwipeHorizontal(int startX, int endX, int yCoordinate, int steps) {
mDevice.swipe(startX, yCoordinate, endX, yCoordinate, steps);
}
public void uiObjectPinch(UiObject view, PinchType direction, int steps,
int percent) throws Exception {
if (direction.equals(PinchType.IN)) {
view.pinchIn(percent, steps);
} else if (direction.equals(PinchType.OUT)) {
view.pinchOut(percent, steps);
}
}
public void uiObjectVertPinch(UiObject view, PinchType direction,
int steps, int percent) throws Exception {
if (direction.equals(PinchType.IN)) {
uiObjectVertPinchIn(view, steps, percent);
} else if (direction.equals(PinchType.OUT)) {
uiObjectVertPinchOut(view, steps, percent);
}
}
public void repeatClickUiObject(UiObject view, int repeatCount, int intervalInMillis) throws Exception {
int repeatInterval = intervalInMillis > CLICK_REPEAT_INTERVAL_MINIMUM
? intervalInMillis : CLICK_REPEAT_INTERVAL_DEFAULT;
if (repeatCount < 1 || !view.isClickable()) {
return;
}
for (int i = 0; i < repeatCount; ++i) {
view.click();
SystemClock.sleep(repeatInterval); // in order to register as separate click
}
}
public UiObject clickUiObject(FindByCriteria criteria, String matching) throws Exception {
return clickUiObject(criteria, matching, null, false);
}
public UiObject clickUiObject(FindByCriteria criteria, String matching, boolean wait) throws Exception {
return clickUiObject(criteria, matching, null, wait);
}
public UiObject clickUiObject(FindByCriteria criteria, String matching, String clazz) throws Exception {
return clickUiObject(criteria, matching, clazz, false);
}
public UiObject clickUiObject(FindByCriteria criteria, String matching, String clazz, boolean wait) throws Exception {
UiObject view;
switch (criteria) {
case BY_ID:
view = (clazz == null)
? getUiObjectByResourceId(matching) : getUiObjectByResourceId(matching, clazz);
break;
case BY_DESC:
view = (clazz == null)
? getUiObjectByDescription(matching) : getUiObjectByDescription(matching, clazz);
break;
case BY_TEXT:
default:
view = (clazz == null)
? getUiObjectByText(matching) : getUiObjectByText(matching, clazz);
break;
}
if (wait) {
view.clickAndWaitForNewWindow();
} else {
view.click();
}
return view;
}
public UiObject getUiObjectByResourceId(String resourceId, String className) throws Exception {
return getUiObjectByResourceId(resourceId, className, uiAutoTimeout);
}
public UiObject getUiObjectByResourceId(String resourceId, String className, long timeout) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().resourceId(resourceId)
.className(className));
if (!object.waitForExists(timeout)) {
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
resourceId, className));
}
return object;
}
public UiObject getUiObjectByResourceId(String id) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().resourceId(id));
if (!object.waitForExists(uiAutoTimeout)) {
throw new UiObjectNotFoundException("Could not find view with resource ID: " + id);
}
return object;
}
public UiObject getUiObjectByDescription(String description, String className) throws Exception {
return getUiObjectByDescription(description, className, uiAutoTimeout);
}
public UiObject getUiObjectByDescription(String description, String className, long timeout) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().descriptionContains(description)
.className(className));
if (!object.waitForExists(timeout)) {
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
description, className));
}
return object;
}
public UiObject getUiObjectByDescription(String desc) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().descriptionContains(desc));
if (!object.waitForExists(uiAutoTimeout)) {
throw new UiObjectNotFoundException("Could not find view with description: " + desc);
}
return object;
}
public UiObject getUiObjectByText(String text, String className) throws Exception {
return getUiObjectByText(text, className, uiAutoTimeout);
}
public UiObject getUiObjectByText(String text, String className, long timeout) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().textContains(text)
.className(className));
if (!object.waitForExists(timeout)) {
throw new UiObjectNotFoundException(String.format("Could not find \"%s\" \"%s\"",
text, className));
}
return object;
}
public UiObject getUiObjectByText(String text) throws Exception {
UiObject object = mDevice.findObject(new UiSelector().textContains(text));
if (!object.waitForExists(uiAutoTimeout)) {
throw new UiObjectNotFoundException("Could not find view with text: " + text);
}
return object;
}
// Helper to select a folder in the gallery
public void selectGalleryFolder(String directory) throws Exception {
UiObject workdir =
mDevice.findObject(new UiSelector().text(directory)
.className("android.widget.TextView"));
UiScrollable scrollView =
new UiScrollable(new UiSelector().scrollable(true));
// If the folder is not present wait for a short time for
// the media server to refresh its index.
boolean discovered = workdir.waitForExists(TimeUnit.SECONDS.toMillis(10));
if (!discovered && scrollView.exists()) {
// First check if the directory is visible on the first
// screen and if not scroll to the bottom of the screen to look for it.
discovered = scrollView.scrollIntoView(workdir);
// If still not discovered scroll back to the top of the screen and
// wait for a longer amount of time for the media server to refresh
// its index.
if (!discovered) {
// scrollView.scrollToBeggining() doesn't work for this
// particular scrollable view so use device method instead
for (int i = 0; i < 10; i++) {
uiDeviceSwipeUp(20);
}
discovered = workdir.waitForExists(TimeUnit.SECONDS.toMillis(60));
// Scroll to the bottom of the screen one last time
if (!discovered) {
discovered = scrollView.scrollIntoView(workdir);
}
}
}
if (discovered) {
workdir.clickAndWaitForNewWindow();
} else {
throw new UiObjectNotFoundException("Could not find folder : " + directory);
}
}
// Override getParams function to decode a url encoded parameter bundle before
// passing it to workloads.
public Bundle getParams() {
// Get the original parameter bundle
parameters = getArguments();
// Decode each parameter in the bundle, except null values and "class", as this
// used to control instrumentation and therefore not encoded.
for (String key : parameters.keySet()) {
String param = parameters.getString(key);
if (param != null && !key.equals("class")) {
param = android.net.Uri.decode(param);
parameters = decode(parameters, key, param);
}
}
return parameters;
}
// Helper function to decode a string and insert it as an appropriate type
// into a provided bundle with its key.
// Each bundle parameter will be a urlencoded string with 2 characters prefixed to the value
// used to store the original type information, e.g. 'fl' -> list of floats.
private Bundle decode(Bundle parameters, String key, String value) {
char value_type = value.charAt(0);
char value_dimension = value.charAt(1);
String param = value.substring(2);
if (value_dimension == 's') {
if (value_type == 's') {
parameters.putString(key, param);
} else if (value_type == 'f') {
parameters.putFloat(key, Float.parseFloat(param));
} else if (value_type == 'd') {
parameters.putDouble(key, Double.parseDouble(param));
} else if (value_type == 'b') {
parameters.putBoolean(key, Boolean.parseBoolean(param));
} else if (value_type == 'i') {
parameters.putInt(key, Integer.parseInt(param));
} else if (value_type == 'n') {
parameters.putString(key, "None");
} else {
throw new IllegalArgumentException("Error decoding:" + key + value
+ " - unknown format");
}
} else if (value_dimension == 'l') {
return decodeArray(parameters, key, value_type, param);
} else {
throw new IllegalArgumentException("Error decoding:" + key + value
+ " - unknown format");
}
return parameters;
}
// Helper function to deal with decoding arrays and update the bundle with
// an appropriate array type. The string "0newelement0" is used to distinguish
// each element for each other in the array when encoded.
private Bundle decodeArray(Bundle parameters, String key, char type, String value) {
String[] string_list = value.split("0newelement0");
if (type == 's') {
parameters.putStringArray(key, string_list);
}
else if (type == 'i') {
int[] int_list = new int[string_list.length];
for (int i = 0; i < string_list.length; i++){
int_list[i] = Integer.parseInt(string_list[i]);
}
parameters.putIntArray(key, int_list);
} else if (type == 'f') {
float[] float_list = new float[string_list.length];
for (int i = 0; i < string_list.length; i++){
float_list[i] = Float.parseFloat(string_list[i]);
}
parameters.putFloatArray(key, float_list);
} else if (type == 'd') {
double[] double_list = new double[string_list.length];
for (int i = 0; i < string_list.length; i++){
double_list[i] = Double.parseDouble(string_list[i]);
}
parameters.putDoubleArray(key, double_list);
} else if (type == 'b') {
boolean[] boolean_list = new boolean[string_list.length];
for (int i = 0; i < string_list.length; i++){
boolean_list[i] = Boolean.parseBoolean(string_list[i]);
}
parameters.putBooleanArray(key, boolean_list);
} else {
throw new IllegalArgumentException("Error decoding array: " +
value + " - unknown format");
}
return parameters;
}
}

@ -0,0 +1,35 @@
/* Copyright 2013-2016 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.wlauto.uiauto;
import android.os.Bundle;
public final class UiAutoUtils {
/** Construct launch command of an application. */
public static String createLaunchCommand(Bundle parameters) {
String launchCommand;
String activityName = parameters.getString("launch_activity");
String packageName = parameters.getString("package_name");
if (activityName.equals("None")) {
launchCommand = String.format("am start --user -3 %s", packageName);
}
else {
launchCommand = String.format("am start --user -3 -n %s/%s", packageName, activityName);
}
return launchCommand;
}
}

@ -0,0 +1,70 @@
/* Copyright 2013-2016 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.wlauto.uiauto;
import android.os.Bundle;
import java.util.logging.Logger;
public class UxPerfUiAutomation extends BaseUiAutomation {
protected String packageName;
protected String packageID;
//Get application package parameters and create package ID
public void getPackageParameters() {
packageName = parameters.getString("package_name");
packageID = packageName + ":id/";
}
public void setWorkloadParameters(Bundle parameters, String packageName, String packageID){
this.parameters = parameters;
this.packageName = packageName;
this.packageID = packageID;
}
public String getPackageID(){
return packageID;
}
private Logger logger = Logger.getLogger(UxPerfUiAutomation.class.getName());
public enum GestureType { UIDEVICE_SWIPE, UIOBJECT_SWIPE, PINCH };
public static class GestureTestParams {
public GestureType gestureType;
public Direction gestureDirection;
public PinchType pinchType;
public int percent;
public int steps;
public GestureTestParams(GestureType gesture, Direction direction, int steps) {
this.gestureType = gesture;
this.gestureDirection = direction;
this.pinchType = PinchType.NULL;
this.steps = steps;
this.percent = 0;
}
public GestureTestParams(GestureType gesture, PinchType pinchType, int steps, int percent) {
this.gestureType = gesture;
this.gestureDirection = Direction.NULL;
this.pinchType = pinchType;
this.steps = steps;
this.percent = percent;
}
}
}

24
wlauto/external/uiauto/build.gradle vendored Normal file

@ -0,0 +1,24 @@
// 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
}

@ -14,8 +14,18 @@
# limitations under the License.
#
# 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
# Build and return appropriate exit code if failed
./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
ant build
cp bin/classes/com/arm/wlauto/uiauto/BaseUiAutomation.class ../../common
cp app/build/outputs/aar/app-debug.aar ../../common/android/uiauto.aar

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="com.arm.wlauto.uiauto" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: VERSION_TAG -->
<import file="${sdk.dir}/tools/ant/uibuild.xml" />
</project>

Some files were not shown because too many files have changed in this diff Show More