Driving the Execution of Android Applications

Android applications have an event driven design where their execution is determined and triggered by input events. Android applications respond to many different types of input events including physical button presses, the rotation of the device, the application being started from the launcher and the WiFi connection dropping. These input events can be combined into millions of unique event sequences of varying lengths. Each of these sequences can potentially trigger erroneous application behavior.

Several projects focus on automatically identifying a subset of event sequences and testing the application behavior using these sequences as input. JPA is based on the design of JPF-AWT and Monkeyrunner, where the task of creating and scripting input sequences is left to the user.

This Section looks at how JPA drives the application execution using Input Scripts.

The Input Script

Input scripts are files in which the user can script sequences of input events that are used to trigger application execution. Each application requires at least one input script for it to run on JPA. Each script is stored in a file with a ``.es'' extension in the project directory. The name of the currently in-use script is configured in the JPF properties file of the SUT as the ``android.script'' property.

JPF-Android's input script follows the grammar of the JPF-AWT scripting language. This scripting language is a dynamically typed, interpreted language. JPA introduces two new constructs: *Sections* and *Groups*. The new grammar of this language is defined in the Figure below using EBNF notation.

<script>     := { <section> }.
<section>    := `SECTION' ( `default' | <id> ) `{' { <sequence> } `}'.
<sequence>   := <iteration> | <selection> | <event>.
<iteration>  := `REPEAT' <num>  `{' <sequence> `}'.
<selection>  :=  `ANY'  `{' <group> { `,'  <group> }  `}'.
<group>      := { <sequence> }.
<event>      :=  <uievent> | <sysevent>
<uievent>    :=  `$' <target> `.'  <action> `('  <params>  `)'.
<sysevent> :=  [`@' <target> `.' | `device' `.' ]   <action> `('  <params>  `)'.
<target>    :=  <id>.
<action>    :=  <id>.
<params>   := [ <param> {, <param> } ].
<param>    := <id> | `"' <id> `"'.
<id>     := <letter> { <letter> | <digit> | `_' }.
<num>      : <digit> { <digit> }.

EBNF of the scripting language

JPA divides the input script into Sections. Each Section in the script groups together the input events of a specific Window. The reason for this is that Android applications contain many Windows, at least one for each Activity. The script, which allows non-deterministic input events, can non-deterministically switch between Windows. If the script continues to execute sequentially after a possible Window switch, the next events might not necessarily be relevant to the current Window on the screen. The JPF-AWT project only verified a single Window so this problem was not considered at the time.

A Section defines a unique name identifying the Window to which its input events are bound. The main Window of an Activity needs to be identified by the name of the Activity. If multiple Activities in the application have the same name, the name needs to be prefixed by the package name of the Activity. The name of the initial Section where the script starts executing is set to ``default''.

The **Repeat** or Repetition construct is used to simplify the script by allowing a user to script a sequence of events that is repeated automatically a certain number of times. Listing shows an example of using the Repeat

REPEAT 2 { 
  eventA
  eventB
}
eventA
eventB
eventA
eventB

JPA also extended the Repeat construct to allow it to contain ANY script elements.

In JPF-AWT the **ANY* or Alternative construct contains a list of events that are each scheduled to execute non-deterministically. JPA extended the Alternative construct to contain a list of **Group} objects, each containing a list of events. Instead of only scheduling the events non-deterministically, JPA now schedules the Groups to execute non-deterministically. JPA also extended these Groups to contain cascaded Alternative and Repeat constructs.

The figure below shows an example of using the **ANY** construct together with the event sequence generated by the scripting environment.

eventZ

ANY {
  GROUP {
    eventA
    eventB
  }
  GROUP {
    eventC
  }
}

eventD

Example of an Any script element

<> Android applications react to two types of input events: **user events** and **system events**.

User Events

User or User Interface (UI) events are triggered by a user interacting with ac{GUI} elements on the screen or with the physical buttons on the device. The input script allows the user to simulate UI events with specific parameters. The syntax for scripting UI events is given in the figure below and consists of three main parts:

<uievent>    :=  `$' <target> `.'  <action> `('  <params>  `)'.

<target>    :=  <id>.

<action>    :=  <id>.

<params>   := [ <param> {, <param> } ].

<param>    := <id> | `"' <id> `"'.

<id>       := <letter> { <letter> | <digit> | `_' }.

UI event syntax

  • **target** the name of a specific widget at which this action is targeted for example a button, checkbox, textbox.
  • **action** the action to perform on the target for example click, enter text, select item in a list.
  • **params** optional, comma separated list of parameters.

*$buttonOK.onClick()*, for example, describes a click action on the OK button and *$list.selectItem(5)* describes selecting the fifth item in list.

System Events

Android applications are also driven by system events. System events are fired by the Android system in response to a change in the system state or by other applications interacting with this application. They include notifications such as the state of the WiFi connection changing when the WiFi signal drops.

The syntax of system events is given in Figure ref{fig:syseventgram}.

<sysevent>  :=  [`@' <target> `.' | `device' `.' ]   <action> `('  <params>  `)'.

<target>    :=  <id>.

<action>    :=  <id>.

<params>   := [ <param> {, <param> } ].

<param>    := <id> | `"' <id> `"'.

<id>       := <letter> { <letter> | <digit> | `_' }.

System event syntax

Although some system events can be triggered manually or by using the shell of the device through the Android Debug Bridge (ADB), JPF-Android aims to trigger all types of system events programmatically. This functionality is very important as certain application behavior can only be triggered by system events. We also need to consider that if the system broadcasts a specific state change, the application can query the system for its state. When the system sends a network change event, for example, it is customary for the application to query the current status of the network to make sure it has the newest version of the network state. For the tools running on the emulator this is inherently true. For JPF-Android, however, this results in not allowing events to be sent from the script directly to the application. These events have to be intercepted and forwarded to the relevant service manager to make sure its state also reflects the change.

JPF-Android allows the user to change the state of the system to induces system events. Examples of these state change events are given in the listing below.

device.setWifi("OFF")
device.setBattery("LOW")
device.sendSMS("084 123 1234", "Test")
device.setGPS("-33.928806","18.415106")

State changes can also be induced from the script by constructing custom Intents. Intent objects are identified in the script by starting with an ``@'' symbol. The properties of the Intent object are set by using the EBNF definition of an event to call the setter methods of the Intent. In the listing below an custom Intent, *@WifiOffIntent* is constructed to disable the WiFi radio.

@WifiOffIntent.setAction("android.net.conn.CONNECTION_CHANGE")
@WifiOffIntent.putExtraString("type", "WIFI")
@WifiOffIntent.putExtraString("state", "DISCONNECTED")
@WifiOffIntent.putExtraString("reason", "NO SIGNAL")

Creating a @WifiOffIntent in the script

Intents constructed in the script have to contain all the necessary information the application expects from the specific type of Intent. The Intent is then broadcast to the Android system using the sendBroadcast system event. Listing ref{fig:start} shows how the Intent is sent to the system.

sendBroadcast(@WifiOffIntent)

Sending a WifiOffIntent Intent from the input script

JPF-Android also predefines common Intents that are used frequently to simplify the script. These Intent objects include Intents used to start an Activity, disable/enable the WiFi and setting the battery status. Custom Intents allow the user to provide more details on the action/event.