1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-31 10:11:17 +00:00

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.
This commit is contained in:
jummp01 2017-01-31 17:50:04 +00:00
parent bd37973442
commit ca7a1abe78
6 changed files with 534 additions and 0 deletions

View File

@ -0,0 +1,169 @@
# Copyright 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.
#
# pylint: disable=attribute-defined-outside-init
import os
from time import sleep
from wlauto import Workload, AndroidBenchmark, AndroidUxPerfWorkload, UiAutomatorWorkload
from wlauto import Parameter
from wlauto import ExtensionLoader
from wlauto import File
from wlauto import settings
from wlauto.exceptions import ConfigError
from wlauto.exceptions import ResourceError
from wlauto.utils.android import ApkInfo
from wlauto.utils.uxperf import UxPerfParser
import wlauto.common.android.resources
class Applaunch(AndroidUxPerfWorkload):
name = 'applaunch'
description = '''
This workload launches and measures the launch time of applications for supporting workloads.
Currently supported workloads are the ones that implement ``ApplaunchInterface``. For any
workload to support this workload, it should implement the ``ApplaunchInterface``.
The corresponding java file of the workload associated with the application being measured
is executed during the run. The application that needs to be
measured is passed as a parametre ``workload_name``. The parameters required for that workload
have to be passed as a dictionary which is captured by the parametre ``workload_params``.
This information can be obtained by inspecting the workload details of the specific workload.
The workload allows to run multiple iterations of an application
launch in two modes:
1. Launch from background
2. Launch from long-idle
These modes are captured as a parameter applaunch_type.
``launch_from_background``
Launches an application after the application is sent to background by
pressing Home button.
``launch_from_long-idle``
Launches an application after killing an application process and
clearing all the caches.
**Test Description:**
- During the initialization and setup, the application being launched is launched
for the first time. The jar file of the workload of the application
is moved to device at the location ``workdir`` which further implements the methods
needed to measure the application launch time.
- Run phase calls the UiAutomator of the applaunch which runs in two subphases.
A. Applaunch Setup Run:
During this phase, welcome screens and dialogues during the first launch
of the instrumented application are cleared.
B. Applaunch Metric Run:
During this phase, the application is launched multiple times determined by
the iteration number specified by the parametre ``applaunch_iterations``.
Each of these iterations are instrumented to capture the launch time taken
and the values are recorded as UXPERF marker values in logfile.
'''
supported_platforms = ['android']
parameters = [
Parameter('workload_name', kind=str,
description='Name of the uxperf workload to launch',
default='gmail'),
Parameter('workload_params', kind=dict, default={},
description="""
parameters of the uxperf workload whose application launch
time is measured
"""),
Parameter('applaunch_type', kind=str, default='launch_from_background',
allowed_values=['launch_from_background', 'launch_from_long-idle'],
description="""
Choose launch_from_long-idle for measuring launch time
from long-idle. These two types are described in the class
description.
"""),
Parameter('applaunch_iterations', kind=int, default=1,
description="""
Number of iterations of the application launch
"""),
Parameter('report_results', kind=bool, default=True,
description="""
Choose to report results of the application launch time.
"""),
]
def __init__(self, device, **kwargs):
super(Applaunch, self).__init__(device, **kwargs)
def init_resources(self, context):
super(Applaunch, self).init_resources(context)
loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
self.workload_params['markers_enabled'] = True
self.workload = loader.get_workload(self.workload_name, self.device,
**self.workload_params)
self.init_workload_resources(context)
def init_workload_resources(self, context):
self.workload.uiauto_file = context.resolver.get(wlauto.common.android.resources.JarFile(self.workload))
if not self.workload.uiauto_file:
raise ResourceError('No UI automation JAR file found for workload {}.'.format(self.workload.name))
self.workload.device_uiauto_file = self.device.path.join(self.device.working_directory, os.path.basename(self.workload.uiauto_file))
if not self.workload.uiauto_package:
self.workload.uiauto_package = os.path.splitext(os.path.basename(self.workload.uiauto_file))[0]
def validate(self):
super(Applaunch, self).validate()
self.workload.validate()
self.pass_parameters()
def pass_parameters(self):
self.uiauto_params['workload'] = self.workload.name
self.uiauto_params['package'] = self.workload.package
self.uiauto_params['binaries_directory'] = self.device.binaries_directory
self.uiauto_params.update(self.workload.uiauto_params)
if self.workload.activity:
self.uiauto_params['launch_activity'] = self.workload.activity
else:
self.uiauto_params['launch_activity'] = "None"
self.uiauto_params['applaunch_type'] = self.applaunch_type
self.uiauto_params['applaunch_iterations'] = self.applaunch_iterations
def setup(self, context):
AndroidBenchmark.setup(self.workload, context)
if not self.workload.launch_main:
self.workload.launch_app()
UiAutomatorWorkload.setup(self, context)
self.workload.device.push_file(self.workload.uiauto_file, self.workload.device_uiauto_file)
def run(self, context):
UiAutomatorWorkload.run(self, context)
def update_result(self, context):
super(Applaunch, self).update_result(context)
if self.report_results:
parser = UxPerfParser(context, prefix='applaunch_')
logfile = os.path.join(context.output_directory, 'logcat.log')
parser.parse(logfile)
parser.add_action_timings()
def teardown(self, context):
super(Applaunch, self).teardown(context)
AndroidBenchmark.teardown(self.workload, context)
UiAutomatorWorkload.teardown(self.workload, context)
#Workload uses Dexclass loader while loading the jar file of the instrumented workload.
#Dexclassloader unzips and generates .dex file in the .jar directory during the run.
device_uiauto_dex_file = self.workload.device_uiauto_file.replace(".jar", ".dex")
self.workload.device.delete_file(self.device.path.join(self.device.binaries_directory, device_uiauto_dex_file))

View File

@ -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 build.xml exists before starting
if [[ ! -f build.xml ]]; then
echo 'Ant build.xml file not found! Check that you are in the right directory.'
exit 9
fi
# Copy base classes from wlauto dist
class_dir=bin/classes/com/arm/wlauto/uiauto
base_classes=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', '*.class')"`
mkdir -p $class_dir
cp $base_classes $class_dir
# Build and return appropriate exit code if failed
ant build
exit_code=$?
if [[ $exit_code -ne 0 ]]; then
echo "ERROR: 'ant build' exited with code $exit_code"
exit $exit_code
fi
# If successful move JAR file to workload folder (overwrite previous)
package=com.arm.wlauto.uiauto.applaunch.jar
rm -f ../$package
if [[ -f bin/$package ]]; then
cp bin/$package ..
else
echo 'ERROR: UiAutomator JAR could not be found!'
exit 9
fi

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="com.arm.wlauto.uiauto.applaunch" 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>

View File

@ -0,0 +1,14 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-18

View File

@ -0,0 +1,220 @@
/* Copyright 2014-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.applaunch;
import android.os.Bundle;
import android.util.Log;
// Import the uiautomator libraries
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.core.UiSelector;
import com.arm.wlauto.uiauto.ApplaunchInterface;
import com.arm.wlauto.uiauto.UxPerfUiAutomation;
import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_ID;
import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_TEXT;
import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_DESC;
import java.util.concurrent.TimeUnit;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Map.Entry;
import dalvik.system.DexClassLoader;
import java.lang.reflect.Method;
public class UiAutomation extends UxPerfUiAutomation {
/**
* Uiobject that marks the end of launch of an application, which is workload
* specific and added in the workload Java file by a method called getLaunchEndObject().
*/
public UiObject launchEndObject;
/** Timeout to wait for application launch to finish. */
private Integer launch_timeout = 10;
public String applaunchType;
public String applaunchIterations;
public String activityName;
public ApplaunchInterface launch_workload;
/** Uiautomator function called by the applaunch workload. */
public void runUiAutomation() throws Exception{
parameters = getParams();
// Get workload jar file parameters
String workload = parameters.getString("workload");
String binariesDirectory = parameters.getString("binaries_directory");
String workloadJarPath = parameters.getString("workdir");
String workloadJarName = String.format("com.arm.wlauto.uiauto.%1s.jar",workload);
String workloadJarFile = String.format("%1s/%2s",workloadJarPath, workloadJarName);
// Load the jar file
File jarFile = new File(workloadJarFile);
if(!jarFile.exists()) {
throw new Exception(String.format("Jar file not found: %s", workloadJarFile));
}
DexClassLoader classloader = new DexClassLoader(jarFile.toURI().toURL().toString(),
binariesDirectory, null, ClassLoader.getSystemClassLoader());
Class uiautomation = null;
Object uiautomation_interface = null;
String workloadClass = String.format("com.arm.wlauto.uiauto.%1s.UiAutomation",workload);
try {
uiautomation = classloader.loadClass(workloadClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Log.d("Class loaded:", uiautomation.getCanonicalName());
uiautomation_interface = uiautomation.newInstance();
// Create an Application Interface object from the workload
launch_workload = ((ApplaunchInterface)uiautomation_interface);
// Get parameters for application launch
getPackageParameters();
applaunchType = parameters.getString("applaunch_type");
applaunchIterations = parameters.getString("applaunch_iterations");
activityName = parameters.getString("launch_activity");
// Run the workload for application launch initialization
runApplaunchSetup();
// Run the workload for application launch measurement
for (int iteration = 0; iteration < Integer.parseInt(applaunchIterations); iteration++) {
Log.d("Applaunch iteration number: ", applaunchIterations);
sleep(20);//sleep for a while before next iteration
killBackground();
runApplaunchIteration(iteration);
closeApplication();
}
}
/**
* Setup run for applaunch workload that clears the initial
* run dialogues on launching an application package.
*/
public void runApplaunchSetup() throws Exception{
setScreenOrientation(ScreenOrientation.NATURAL);
launch_workload.setWorkloadParameters(parameters);
launch_workload.runApplicationInitialization();
launchEndObject = launch_workload.getLaunchEndObject();
unsetScreenOrientation();
closeApplication();
}
/**
* This method performs multiple iterations of application launch and
* records the time taken for each iteration.
*/
public void runApplaunchIteration(Integer iteration_count) throws Exception{
String testTag = "applaunch" + iteration_count;
String launchCommand = launch_workload.getLaunchCommand();
AppLaunch applaunch = new AppLaunch(testTag, launchCommand);
applaunch.startLaunch();//Launch the application and start timer
applaunch.endLaunch();//marks the end of launch and stops timer
}
/*
* AppLaunch class implements methods that facilitates launching applications
* from the uiautomator. It has methods that are used for one complete iteration of application
* launch instrumentation.
* ActionLogger class is instantiated within the class for measuring applaunch time.
* startLaunch(): Marks the beginning of the application launch, starts Timer
* endLaunch(): Marks the end of application, ends Timer
* launchMain(): Starts the application launch process and validates the finish of launch.
*/
private class AppLaunch {
private String testTag;
private String launchCommand;
private ActionLogger logger;
Process launch_p;
public AppLaunch(String testTag, String launchCommand) {
this.testTag = testTag;
this.launchCommand = launchCommand;
this.logger = new ActionLogger(testTag, parameters);
}
// Called by launchMain() to check if app launch is successful
public void launchValidate(Process launch_p) throws Exception {
launch_p.waitFor();
Integer exit_val = launch_p.exitValue();
if (exit_val != 0) {
throw new Exception("Application could not be launched");
}
}
// Marks the end of application launch of the workload.
public void endLaunch() throws Exception{
waitObject(launchEndObject, launch_timeout);
logger.stop();
launch_p.destroy();
}
// Launches the application.
public void launchMain() throws Exception{
launch_p = Runtime.getRuntime().exec(launchCommand);
launchValidate(launch_p);
}
// Beginning of application launch
public void startLaunch() throws Exception{
logger.start();
launchMain();
}
}
// Exits the application according to application launch type.
public void closeApplication() throws Exception{
if(applaunchType.equals("launch_from_background")) {
pressHome();
}
else if(applaunchType.equals("launch_from_long-idle")) {
killApplication();
dropCaches();
}
}
// Kills the application process
public void killApplication() throws Exception{
Process kill_p;
kill_p = Runtime.getRuntime().exec(String.format("am force-stop %s", packageName));
kill_p.waitFor();
kill_p.destroy();
}
// Kills the background processes
public void killBackground() throws Exception{
Process kill_p;
kill_p = Runtime.getRuntime().exec("am kill-all");
kill_p.waitFor();
kill_p.destroy();
}
// Drop the caches
public void dropCaches() throws Exception{
Process drop_cache;
drop_cache = Runtime.getRuntime().exec("su sync; su echo 3 > /proc/sys/vm/drop_caches");
drop_cache.waitFor();
drop_cache.destroy();
}
}