Diploma Thesis
Diploma Thesis
Diploma Thesis
Faculty of Informatics
Master’s Thesis
Marek Osvald
Master’s Thesis
Marek Osvald
Marek Osvald
i
Acknowledgement
This work was carried out during the years 2016-2017 at AVG Technolo-
gies CZ and the Faculty of Informatics at the Masaryk University in
Brno. It is a pleasure to use this page to sincerely thank all the people
contributing or otherwise involved in the development of this thesis.
I owe my deepest gratitude to my thesis supervisor, professor
Václav Matyáš. His continuous support helped me to write a thesis
worthy of a prestigious institution such as the Masaryk University.
I am deeply grateful to my technical supervisor Petr Koudelka for
his continuous optimism and guidance during the development. His
advise helped me on countless occasions.
I would like to express my most sincere gratitude to Philip M.
Gammon who answered my English-related questions and selflessly
offered proofreading this text.
I am particularly grateful for support given by Katarína Varačková
and Petr Buno during the initial prototype development. Their contri-
bution helped to speed up the work on the prototype tremendously
and it was truly a pleasure to work with both of them.
I want to express my gratitude to Marcel Kappler and Marting Šůs
for their help integrating the solution with AVG’s existing infrastruc-
ture. Their help was simply invaluable.
I am also in debt to Jan Švábenský who helped me to devise the
testing strategy and for his insight during integration testing. His
expertise helped me to learn a great lot about testing, QA automation
and the underlying technology.
I would also like to thank Lucie Lénertová, Karel Ovesný, Libor
Jancek, and Dominik Pokora for their comments during the GUI sup-
port tool development.
And last but definitely not least, I owe an endless debt of gratitude
to my parents, Martina Osvaldová and Martin Osvald. They have tire-
lessly supported me throughout my entire academic career. Without
their love, emotional and financial support this thesis would have
never been possible. Thank you for being the way you are and helping
me in every single imaginable way to achieve my goals and dreams.
This text is dedicated to you.
iii
Abstract
The goal of this master’s thesis is to develop a universal and adapt-
able solution for crash reporting of Android applications. The thesis
describes the entire development process of such solution, from its
architecture concepts to the process of deployment including a test
plan and means of its automation.
iv
Keywords
Android, crash reporting, Google Play, JUnit, Mockito, PowerMock,
Appium, TSD, autolib, Final-CI, Artifactory
v
Contents
1 Introduction 1
3 Technologies Used 9
3.1 Programming Languages . . . . . . . . . . . . . . . . . . . 9
3.2 Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3 Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4 Implementation 15
4.1 Analysis of Existing Solutions . . . . . . . . . . . . . . . . 15
4.1.1 ACRA . . . . . . . . . . . . . . . . . . . . . . . . 15
4.1.2 HockeyApp . . . . . . . . . . . . . . . . . . . . . 16
4.1.3 Crashlytics . . . . . . . . . . . . . . . . . . . . . . 17
4.2 Architecture Concept . . . . . . . . . . . . . . . . . . . . . 21
4.3 Handling Managed Code Crashes . . . . . . . . . . . . . . 23
4.3.1 Collecting Metadata . . . . . . . . . . . . . . . . 26
4.4 Handling Native Code Crashes . . . . . . . . . . . . . . . . 28
4.4.1 Google Breakpad Integration . . . . . . . . . . . 31
4.4.2 Initialising the Native Code Handler . . . . . . . 34
4.4.3 Collecting Metadata . . . . . . . . . . . . . . . . 34
4.5 Notifying the User . . . . . . . . . . . . . . . . . . . . . . 35
4.6 Providing Crash Data . . . . . . . . . . . . . . . . . . . . . 41
4.6.1 Default Synchronous Providers . . . . . . . . . . 42
4.6.2 Default Asynchronous Providers . . . . . . . . . 44
4.7 Configuration Management . . . . . . . . . . . . . . . . . 47
4.7.1 Application Identification Options . . . . . . . . 49
4.7.2 User Notification Options . . . . . . . . . . . . . 50
4.7.3 Provider Options . . . . . . . . . . . . . . . . . . 51
4.7.4 Data Publishing Options . . . . . . . . . . . . . . 51
4.7.5 Connection Options . . . . . . . . . . . . . . . . 52
4.7.6 Logging Options . . . . . . . . . . . . . . . . . . 53
4.8 Packaging of collected data . . . . . . . . . . . . . . . . . . 53
4.8.1 The BinPacker File Format . . . . . . . . . . . . . 53
vii
4.8.2 BinPacker API . . . . . . . . . . . . . . . . . . . . 55
4.8.3 Support Tools . . . . . . . . . . . . . . . . . . . . 56
4.9 Data Publishing . . . . . . . . . . . . . . . . . . . . . . . . 57
4.9.1 CAP Crash Publisher . . . . . . . . . . . . . . . . 58
4.9.2 External Storage Publisher . . . . . . . . . . . . . 60
4.9.3 Publishing Strategies . . . . . . . . . . . . . . . . 60
4.10 Connection Handling . . . . . . . . . . . . . . . . . . . . . 61
4.10.1 Offline Publisher . . . . . . . . . . . . . . . . . . 63
4.10.2 Publishing Attempts . . . . . . . . . . . . . . . . 63
4.11 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.11.1 Logging API . . . . . . . . . . . . . . . . . . . . . 65
4.12 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.12.1 Unit Testing . . . . . . . . . . . . . . . . . . . . . 66
4.12.2 Integration Testing . . . . . . . . . . . . . . . . . 68
4.12.3 Mock CAP Server . . . . . . . . . . . . . . . . . . 73
4.12.4 Automation . . . . . . . . . . . . . . . . . . . . . 74
4.13 Building . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.13.1 Building the Library . . . . . . . . . . . . . . . . 75
4.13.2 Building the Simulator . . . . . . . . . . . . . . . 76
4.13.3 Building the Mock CAP Server . . . . . . . . . . 78
4.13.4 Additional Gradle Tasks . . . . . . . . . . . . . . 79
4.14 Publishing . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5 Conclusion 83
Bibliography 85
viii
List of Figures
2.1 Standard Android 7.1.2 Crash Dialogs. 6
4.1 Example of ACRA’s Dialog Window. 17
4.2 HockeyApp’s Dialog Window. 18
4.3 Example of HockeyApp Server Crash Reports. 19
4.4 Example of Fabric Crashlytics Dashboard. 20
4.5 Sequence Diagram: Handling Managed Code
Crashes. 24
4.6 Sequence Diagram: Handling Native Code
Crashes. 30
4.7 Google Breakpad Architecture. 32
4.8 Example of Error Activity Stylised as the Windows 10
BSoD. 37
4.9 Example of the Crash Reporting Library Dialog
Window. 38
4.10 Example of the Crash Reporting Library Error
Notification. 39
4.11 Example of the Crash Reporting Library Toast
Message. 40
4.12 Sample Memory Heap Dump Processed in Eclipse
MAT. 43
4.13 Class Diagram: Synchronous Providers. 44
4.14 Class Diagram: Asynchronous Providers. 45
4.15 Visualisation of the BinPacker File Format. 54
4.16 The BinUnPacker Batch Tool. 56
4.17 The BinUnPackerUI GUI Tool. 57
4.18 Class Diagram: Logging. 65
4.19 Example of a TSD Opened in TSD Debugger. 75
4.20 Example of a Test Run Configuration in Final-CI. 76
4.21 The Crash Reporting Library Artifactory Dossier. 80
ix
1 Introduction
AVG Technologies is one of the leading security software companies
targeting the global market. While traditionally being the most known
for its PC products, AVG has launched its mobile application portfolio
in 2010. In order to improve the quality of its products developed for
mobile platforms, AVG has launched a series of research and develop-
ment projects in order to improve the quality of its mobile application
portfolio and to streamline and facilitate the development process.
The goal of one of these projects was to research the means of report-
ing application errors and to provide a universal solution that would
support all of AVG’s products for the Android platform.
Since AVG had already owned an infrastructure for handling crash
reports of desktop applications, the desired goal was to implement
a solution utilising the aforementioned infrastructure but also, not
to be entirely dependent on it in case of any changes in technology.
The proposed solution was meant to also utilise existing build and
automation framework available at AVG.
This thesis describes the entire development process of a custom
crash reporting solution for Android applications within its five chap-
ters. This chapter briefly describes the contents of this thesis.
Chapter 2 defines the problems this thesis aims to solve. Section 2.1
describes the nature of crashes on Android and how they manifest to
the user. It also describes the differences between managed code and
native code crashes. Section 2.2 describes the phases of the develop-
ment cycle where crash reporting might be required and their specifics.
The section also states the questions this thesis aims to answer.
Chapter 3 describes the technologies used during the development
of the proposed solution. Section 3.1 describes the programming lan-
guages chosen for implementation and testing. Section 3.2 describes
tools that aided the development process. And finally, Section 3.3 de-
scribes both open-source and proprietary libraries that are used by
the proposed crash reporting solution.
Chapter 4 describes the actual implementation of the proposed so-
lution. Section 4.1 starts the chapter with an analysis of crash reporting
solutions available for Android applications. This section compares
1
1. Introduction
their respective strengths and weaknesses and argues the point for
developing a custom crash reporting solution.
Section 4.2 explains the basic architecture concept of the proposed
solution, how the library is structured and its fundamental building
blocks and terminology.
Section 4.3 describes the API for detecting and handling managed
code crashes and the process of collecting crash report related meta-
data.
Section 4.4 explains the process of detection and handling native
code crashes and the integration of the Google Breakpad library used
for generating memory minidumps. The section also describes the
differences between collecting metadata for managed code crashes
and native code crashes.
Section 4.5 describes how the proposed solution replaces the de-
fault Android crash dialog window with a customisable user notifica-
tion. The section provides illustrations of possible configurations and
explains the difference in behaviour between different build configu-
rations of the Crash Reporting Library.
Section 4.6 explains how the proposed solution retrieves data used
for crash reporting and the difference between synchronous and asyn-
chronous data providers.
Section 4.7 lists all of the configuration options available in the
Crash Reporting Library, their respective default values and describes
how its API can be utilised to override the default configuration.
Section 4.8 defines the custom light-weight BinPacker File Format
that is used for crash reporting. The section also describes the capabil-
ities of the support tools handling the custom file format and how to
use them.
Section 4.9 explains how the Crash Reporting Library is integrated
within AVG’s existing infrastructure and how its API can be used
in order to process crash reports in multiple ways. The Section also
explains how the Crash Reporting Library can utilise different publish-
ing strategies and when the crash report is considered successful or
unsuccessful.
Section 4.10 describes how the Crash Reporting Library handles
offline states and unsuitable connection types. The Section also in-
troduces the Offline Publisher and explains its role within the Crash
Reporting Library.
2
1. Introduction
Section 4.11 describes the API that the Crash Reporting Library uses
for logging and how this API can be used to integrate the Crash Re-
porting Library logging with the host application.
Section 4.12 describes the testing and automation strategy for the
Crash Reporting Library and explains the process and environment of
the integration testing.
Section 4.13 describes the build configurations of the Crash Report-
ing Library and the support applications. The section also lists Gradle
tasks that can be used to produce one or more solution artefacts.
Section 4.14 defines the process of publishing and deployment the
developed library into a repository owned and maintained by AVG.
And finally, Chapter 5 provides a brief summary of the achieved
results, including author’s personal contribution. The Chapter also
lists the value provided to the industrial partner and highlights ac-
complishments.
3
2 The Problem Defined
This chapter defines the problem this thesis aims to solve and the
technical parameters and constraints of any viable solution.
5
2. The Problem Defined
6
2. The Problem Defined
7
3 Technologies Used
This chapter describes all of the programming languages, libraries,
APIs, tools and other technologies used during the entire development
of the Crash Reporting Library.
9
3. Technologies Used
10
3. Technologies Used
ment for the Bourne shell, first released in 1989. Bash upholds the
POSIX standard for OS shell and provides various extensions.
Bash is used in the automated build verification process, where it
runs the unit tests for build verification and as a language of choice
for Google Breakpad extension’s build script.
3.2 Tools
Android provides two standard APIs for application development,
the Android API for Java and Kotlin and the Android Native API for
C and/or C++.
Android SDK (Android Software Development Kit) [16] is a col-
lection of libraries, compilers, preprocessors and tools which allow
the development of applications for Android using the standard Java
Android APIs.
Android uses a different bytecode than Oracle-compatible VMs,
with compiled classes usually denoted by the .dex file extension. The
original (now called legacy) toolchain would compile Java source files
into Java bytecode classes and then transcompile them using the dx
tool.
The newer Jack toolchain produces .dex files directly. A comple-
mentary library tool called Jill (Jack Intermediate Library Linker) can
be used to transcompile standard Java libraries distributed in the .jar
format [11]. The new Java 8.0 compatible compiler uses the same
approach as the legacy compiler.
There are two virtual machines for Android: the original Dalvik
Virtual Machine and its replacement ART (Android Runtime). Dalvik
originally interpreted the bytecode however, Android version 2.2 (API
level 8, codename Froyo) introduced the JIT (Just-in-Time) compilation
for special cacheable parts of the code called traces [17].
ART was introduced as an experimental feature in Android 4.4
(API level 19, codename KitKat) and ultimately replaced Dalvik as the
default virtual machine in Android 5.0 (API level 21, codename Lol-
lipop). ART uses the AoT (Ahead of Time) compilation. The bytecode
gets compiled during the application installation, thus completely
eliminating Dalvik’s interpretation and JIT trace-based compilation.
This led to an optimisation during runtime, a better performance and
11
3. Technologies Used
3.3 Libraries
12
3. Technologies Used
JUnit [22] is one of the most popular frameworks for the develop-
ment, running and configuration management of unit tests written
in Java. The latest stable version is 4.12. A new overhauled version
5.0 targeted for and using new features of Java 8.0 was released in
September 2017 [22]. All unit tests of the Crash Reporting Library and
its support tools were written using JUnit 4.
Mockito [23] is an open-source testing framework for Java. An-
droid does support local unit tests2 using the android.jar library
included in the Android SDK. However, all of the classes contained in
the android.jar are mere stubs3 .
In order to implement a locally run unit test, one does need to
provide a custom test implementation of all of the dependency classes
located in the Android SDK. This is usually achieved either through
inheritance of classes and interfaces or, preferably by using a mocking
library. Mockito is used in unit tests of the Crash Reporting Library.
PowerMock [25] is Java framework dedicated to solving common
testing problems, obstacles and pitfalls. PowerMock provides two
API extensions: one for Mockito (called PowerMockito) and one for
EasyMock.
PowerMock allows for mocking and testing implementation even
of final and static methods and classes by manipulating the code on
the VM/bytecode level and hence simulating otherwise unreachable
states required by unit testing. PowerMockito is used in unit tests of
the Crash Reporting Library.
Google Breakpad [26] is an open-source library developed by
Google used for handling native code crashes and generating memory
dumps. Google Breakpad is usable on several platforms including
Microsoft Windows, Linux, macOS and Android amongst others.
A successor library named Google Crashpad is currently under
development. However, Crashpad does not support Android at the
moment [27]. Google Breakpad is used in the native code crash report-
ing loop within the Crash Reporting Library.
Appium [28] is an open-source tool for test automation of native,
web-based and hybrid applications for iOS and Android platforms.
2. Meaning the tests are run on a development machine not on the actual handset,
tablet or other device with Android.
3. Blank implementations formally returning default values and throwing
RuntimeException [24] upon each call of any method from the archive.
13
3. Technologies Used
14
4 Implementation
This chapter defines the process of implementation from the initial
analysis of existing solutions to the testing and automation process.
• further extensibility,
4.1.1 ACRA
Application Crash Reports for Android (ACRA) is an open-source
library developed by Kevin Gaudin, enabling Android applications
to automatically post their crash reports to a report server [31]. In
February 2016, ACRA was used in 2.68% of applications available on
Google Play. The latest version is 4.10.0, released in June 2017. ACRA’s
source code was released under the Apache License 2.0 license.
ACRA requires the android.permission.INTERNET permission
which is automatically granted on devices with Android 6.0 or newer
and granted upon installation on devices with older versions of An-
droid.
ACRA’s architecture utilises a handler service running in its own
process. This allows to terminate the crashing process and immediately
send the crash report to a server.
The service is meant to be started within the android.app.
Application#attachBaseContext(Context) method.
15
4. Implementation
There are two ways how one can initialise and pass configuration
to ACRA. The first one is by adding the @ReportCrashes annotation
located in the org.acra.annotation package to the Application class
and initialising ACRA via the org.acra.ACRA.init(Application)
method call. The other way uses a configuration builder class and ini-
tialises the library by calling the org.acra.ACRA.init(Application,
ConfigurationBuilder) method.
There are several back-end implementations for ACRA written in
various languages such as Java, Ruby and Go amongst others [32].
ACRA prescribes a standard behaviour to which a server must comply
and provides a referential implementation named Acralyzer [33].
On top of that, ACRA allows for custom publishing mechanisms
to support custom and third party servers (see Subsection 4.1.2).
ACRA does not support crash reporting for native code crashes. A
third party adapter called Acra-breakpad [34] exists, using a modified
version of ACRA [35]. However, Acra-breakpad seems outdated and
no longer actively developed as the last update was released on 15
March 2014.
ACRA can also suppress the default dialog window (see Figure 2.1).
ACRA supports four different modes for user notification whenever an
application crash is detected: DIALOG (displaying a customisable dialog
window, see Figure 4.1), NOTIFICATION (displaying a system notifica-
tion in the status bar), TOAST (displaying a Toast message [36]) and the
so-called SILENT mode, which does not display any user notification.
4.1.2 HockeyApp
16
4. Implementation
4.1.3 Crashlytics
Crashlytics is a proprietary SDK originally developed by a company
of the same name. In January 2013, Twitter, Inc. acquired Crashlytics
17
4. Implementation
[39] and maintained its development tools until January 2017, when
it was acquired by Google who currently plan to merge Crashlytics
with their Firebase initiative [40].
Crashlytics supports Android crash reporting since May 2013 [41].
In May 2015, a support for native code crashes was announced. In
October 2014, Crashlytics became a part of Fabric – a larger portfolio of
mobile application analytic, user identity and authentication tools [40].
Crashlytics supports Android 2.2 (API level 8, codename Froyo)
or newer. The NDK crash reporting supports all NDK architec-
tures. Crashlytics requires a single system permission, the android.
permission.INTERNET.
Crashlytics supports Ant, Maven and Gradle build systems [42].
Gradle projects are required to use a specialised Gradle plug-in that
processes the Crashlytics settings.
Similarly to HockeyApp, Crashlytics uses a proprietary back-end
server solution accessible via an API key stored in the Android man-
ifest. The crash reports can be viewed using the Fabric Crashlytics
Dashboard (see Figure 4.4).
18
4. Implementation
Crashlytics does not override the default crash dialog window (see
Figure 2.1).
Conclusion
All three of the aforementioned solutions lack the desired universality.
While ACRA provides the desired level of configurability and techno-
logical independence of any particular back-end solution, it does not
handle native code crashes. Conversely, HockeyApp and Crashlytics
do support native code crash reporting but lack the configurability
and require their respective proprietary servers. To change the default
behaviour would mean significantly modifying the source code which
cannot be done for Crashlytics since its source code is undisclosed.
HockeyApp’s crash reporting after an application restart is an
impractical solution for automated integration tests and maintaining
19
4. Implementation
20
4. Implementation
21
4. Implementation
22
4. Implementation
23
4. Implementation
24
4. Implementation
25
4. Implementation
The crash report data and metadata are stored in the com.avg.
zaap.crashlibrary.ReportData class that implements the android.
os.Parcelable interface. The class is mutable and serves further the
data structure for other processing classes, such as CrashReporter, the
asynchronous providers and publishers amongst others (see Sections 4.6,
4.9 and 4.10).
Finally, the host process gets terminated by calling the
android.os.Process.killProcess(int) method and the crash
report files are handled further by the CrashReportingService.
26
4. Implementation
Internal Metadata
Identification Metadata
While the Crash Reporting Library aims to support multiple crash re-
porting server solutions, the main goal is to integrate it within AVG’s
existing crash reporting infrastructure.
The proprietary AVG back-end solution requires a particular set of
data to analyse and process the crash. This subsection describes the
metadata collected for identification, classification and grouping of
crash reports.
27
4. Implementation
Java provides an API for calling native code and passing data between
native and managed code called JNI (Java Native Interface). Native
code methods are declared without an implementation (similarly to
28
4. Implementation
29
4. Implementation
30
4. Implementation
31
4. Implementation
1. The armeabi ABI is now considered deprecated and support for it will be re-
moved in an upcoming release of the Android NDK.
32
4. Implementation
#include "client/linux/handler/exception_handler.h"
#include "android_breakpad.h"
using namespace google_breakpad;
$NDK/build/tools/make-standalone-toolchain.sh --arch=arm
--abis=armeabi --platform=android-19 --ndk-dir=$NDK
--install-dir=$HOME/toolchains/armeabi-platform19
64-bit Intel CPUs). Google Breakpad for each supported platform can
be built using the respective exported stand-alone toolchain.
Google Breakpad client can be configured by using the configure
script and compiled using the make script (see Source code 3).
Google Breakpad client is distributed as static library named
libbreakpad_client.a. The Crash Reporting Library encapsulates the
static library into a shared library named libandroid_breakpad.so.
./configure --host=arm-linux-androideabi
--disable-processor --disable-tools
make -j4
33
4. Implementation
34
4. Implementation
Internal Metadata
Error Name, Error Message and Error Details values are unused and
left empty.
Crash Code is equal to the GUID generated by Google Breakpad
(omitting the .dump file extension).
Files to Pack value contains only the Google Breakpad memory
dump file path, since Google Breakpad generates only one file.
Identification Metadata
Exception Code is derived from the GUID generated by Google
Breakpad and adding adding a 0x prefix (i.e. the Crash code for
9c95312e-bf5d-4547-8036-616e85124b9f.dump is 0x9c95312e).
Module Version, Process Version and GUID are collected the
same way as for the managed code crashes (see Subsection 4.3.1).
Faulting Offset, Module Name and Process Name values are set
to constants. Faulting offset is set to 0 and both Module Name and
Process Name are set to native, denoting a native code crash.
35
4. Implementation
ERROR_SCREEN
When the ERROR_SCREEN configuration value is set, whenever the
Crash Reporting Library detects a crash, it displays the com.avg.zaap.
crashlibrary.show.error.activity.ErrorActivity and puts it on
top of the navigation stack.
Since XML resources are merged between library and appli-
cation projects, the layout can be customised by overriding the
activity_error.xml layout file located in the src/res/layout di-
rectory.
While it is not enforced, the provided layout should contain the
following Views:
36
4. Implementation
37
4. Implementation
and is set as the default value in the Crash Reporting Library configura-
tion management.
DIALOG
When the DIALOG configuration value is set, whenever the Crash Report-
ing Library detects a crash, it displays a customisable dialog window
informing a user about the crash.
Android does allow displaying a system-level alert dialog window
that overlaps other applications (including the launcher and other
previously launched applications). Such dialog requires the android.
permission.SYSTEM_ALERT_WINDOW permission. Usage of this permis-
sion is discouraged, as creating the system-level windows is meant to
be reserved for system-level interaction with the user.
Moreover, since the Android 6.0 (API level 23, codename Marsh-
mallow) permission overhaul, this permission is so-called extra pro-
tected which means the standard permission requesting dialog does
not pop up for SYSTEM_ALERT_WINDOW [54]. Therefore, the user has to
manually grant the permission to an application using the standard
Android Settings application. In conclusion, this solution is not viable
for applications targeting the API level 23 or higher for reliable crash
reporting and user notification.
38
4. Implementation
NOTIFICATION
When the NOTIFICATION configuration value is set, whenever the Crash
Reporting Library detects a crash, it displays a customisable system
notification in the status bar (see Figure 4.10).
The notification sets the errorMessage configuration option as the
notification title and the errorDetails configuration option as the
notification message.
39
4. Implementation
TOAST
When the TOAST configuration value is set, whenever the Crash Re-
porting Library detects a crash, it displays a Toast system message
(see 4.11). The errorDetails configuration option is set as the Toast
message text. The Toast is displayed for the android.widget.Toast.
LENGTH_SHORT interval (2 seconds on standard devices).
This configuration value is similar to ACRA’s TOAST reporting in-
teraction mode.
NONE
When the NONE configuration value is set, whenever the Crash Reporting
Library detects a crash, the user does not get notified in any way. This
mode is predominantly meant for test builds, automation and unstable
release candidates. Not notifying the user does not prevent the crash
data from being collected and published (see Section 4.9).
This configuration value is equivalent to ACRA’S SILENT reporting
interaction mode.
40
4. Implementation
The former group includes all of the data related to the mem-
ory allocated by the crashing process. Such data needs to be
collected before the actual process termination – most notably
the data describing a memory state, such as the stacktrace or
the heap memory dump. The Crash Reporting Library calls the
providers of such data synchronous providers as they actively block
the CrashUncaughtExceptionHandler’s thread until all of requested
data is collected. All synchronous providers implement the com.avg.
zaap.crashlibrary.provider.ICrashSyncProvider interface.
The latter group contains data of either constant or persistent na-
ture. This includes identifiers necessary for reproducing the crash,
such as application build version, hardware ID, manufacturer and
also persistently stored data such as database journals, logs and
possibly other useful application diagnostic data. The Crash Re-
porting Library calls these data providers asynchronous providers. All
asynchronous providers implement the com.avg.zaap.crashlibrary.
provider.ICrashAsyncProvider interface.
Each provider defines a file name where it stores its result data. This
value is mandatory and each provider is expected to store all of the col-
lected information in the specified file for the data to be reported. The
Crash Reporting Library stores these files in a directory named crash
in the application internal storage space (/data/data/<application
package> /crash/ on standard devices). The provider files are meant
to be temporary and are overwritten each time a new crash report is
detected. The Crash Reporting Library does not restrict collision and is
up to the application developer to provide non-colliding names. The
provider files are further compiled into a single file during the crash
report processing (see Section 4.8).
41
4. Implementation
42
4. Implementation
In order to access the memory dump data, the memory dump has
to be converted first by the hprof-conv tool to the standard HPROF
format. Then the memory dump can be processed using standard
tools such as Eclipse MAT (Memory Analysis Tool, see Figure 4.12)
or Oracle’s jhat which is a part of the standard JDK. Android Studio
can open and process the Dalvik HPROF files on its own using the
aforementioned SDK tools.
The Memory Heap Provider stores its data in the dump.dalvik.
hprof output file.
43
4. Implementation
The Device Info Provider collects the data available in the android.os.
Build class such as device brand, manufacturer, model, serial number
and ABIs supported by the device’s CPU amongst others. This data
is meant to provide additional information in order to pinpoint any
problems regarding a customised Android build, a particular vendor
or a device.
44
4. Implementation
45
4. Implementation
Board: sailfish
Bootloader: 8996-012001-1709121620
Brand: google
Device: sailfish
Display: OPR3.170623.013
HW: sailfish
Host: vpef8.mtv.corp.google.com
ID: OPR3.170623.013
Manufacturer: Google
Model: Pixel
Product: sailfish
Serial: FA6AS0301099
SDK: 26
Tags: release-keys
Type: user
User: android-build
ABIs: arm64-v8a, armeabi-v7a, armeabi
46
4. Implementation
APPLICATION_ID : com.avg.zaap.crashlibrary
BUILD_TYPE : debug
DEBUG : true
FLAVOR :
VERSION_CODE : 3
VERSION_NAME : 0.0.3
The data is stored in the same format as the Crash Library Info
Provider data (see Source code 5). In fact, the Crash Library Info
Provider is implemented using the BuildConfigProvider.
47
4. Implementation
import android.app.Application;
import com.avg.zaap.crashlibrary.CrashLib;
import com.avg.zaap.crashlibrary.config.EShowErrorType;
Source code 6: Initialising the Crash Reporting Library Via the Builder.
48
4. Implementation
import android.app.Application;
import com.avg.zaap.crashlibrary.config.
CrashLibConfigAnnotations;
import com.avg.zaap.crashlibrary.config.EShowErrorType;
@CrashLibConfigAnnotations(
showErrorType = EShowErrorType.ERROR_SCREEN,
errorMessage = "Sample error message",
errorDetails = "Sample error details",
disableMemoryHeapProvider = true,
disableStackTraceCrashingThread = true,
disableStackTraceAllThreads = true,
maxAttempts = 10,
delay = 60 * 1000
)
public class CrashApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
CrashLib.init(this);
}
}
49
4. Implementation
the semantic versioning pattern [55]. The host application may specify
any valid string as its applicationVersion. The default value is set to
"unknown".
The capProductID (CAP stands for Crash Analysis Portal) config-
uration option specifies the host application product ID. The host
application may specify any valid string as its capProductID. The
default value is set to "ANDR".
50
4. Implementation
51
4. Implementation
52
4. Implementation
53
4. Implementation
compiling provider files into a single one, in order to save the effort of
developing custom file format and support tools. The initial prototype
used the ZIP algorithm since Java already provides a standard API
for handling standard ZIP and GZIP file formats within the standard
Java API [57].
However, as it had turned out during the empiric observation, the
implementation is too computationally demanding for mobile devices.
This issue naturally affects older single-CPU devices the most. On
older devices even when using the STORE compression level2 , compil-
ing the collected data may take up to several minutes.
Since the main goal of the Crash Reporting Library is to reach max-
imal possible universality, even these older devices are meant to be
supported. The Crash Reporting Library therefore uses a proprietary
light-weight file format named BinPacker File Format.
The BinPacker File Format does not provide file compression and
stores only the minimal amount of metadata. Unlike ZIP or GZIP, the
BinPacker File Format does not support hierarchical directory structure.
However, a root directory can be specified by using a directory header
(see below). A BinPacker File Format file can be identified by the .bp
2. Meaning the ZIP archive is not compressed and actually takes more disk space
than the sum of the original files.
54
4. Implementation
file extension. Files compiled into a BinPacker File Format file are from
hereinafter referred to as binpacked.
Each BinPacker File Format archive consists of two parts – the archive
header and the archive content. The archive header is a null-terminated
UTF-8 string (similar to strings in the C programming language). If
the archive header is equal to the archive file name, the archive does
not define a root directory. Otherwise the archive header specifies
a root directory that is created upon the archive extraction.
The archive content consists of one or more file records. A record
contained within a BinPacker archive has exactly three parts:
55
4. Implementation
56
4. Implementation
destination path using standard file dialogs and to set the default
extraction directory. The BinPackerUI tool also allows to specify auto-
matic overwrite and/or safe extract strategy (see Figure 4.17).
The BinPackerUI tool is distributed as an executable .jar archive.
57
4. Implementation
58
4. Implementation
-1 ERROR
Signalises either communication breakdown or server error.
0 NO_DUMP
No more crash reports of given type are needed, CAP has al-
ready collected sufficient amount of samples.
1 MINI_DUMP
Minidump upload requested.
2 FULL_DUMP
Full dump upload requested.
6 KEEP_DUMPS
No more crash reports of given type needed, the client is ad-
vised to keep recorded dumps for further investigation.
8 DIRECT_CFG
Forces to reload the configuration of the crash reporter (not
implemented).
59
4. Implementation
The crash reporting server pairs the report request and upload
request using the Product ID and randomly generated GUID. Both of
these values are the same for both requests. The Crash Reporting Library
solution also contains a mock implementation of the CAP server for
integration testing purposes (see Section 4.12).
The CAP Publisher is enabled by default and can be disabled using
the configuration management (see Subsection 4.7.4).
60
4. Implementation
Since publishers are independent from each other, one publisher may
return success, while other one reports its result as a failure.
Therefore, the Crash Reporting Library provides three possible pub-
lishing strategies:
• ALL,
• ANY and
• BEST_EFFORT.
61
4. Implementation
1. NONE,
2. OTHER,
3. MOBILE and
4. WIFI
62
4. Implementation
63
4. Implementation
4.11 Logging
This section defines the logging API used in the Crash Reporting Library
and the means of possible extension.
Android replaces the Java Logging API defined in the java.util.
logging package with its own. The standard Android Logging API for
Java is implemented in the android.util.Log class [58]. The Android
logging API defines the following severity levels:
2. DEBUG,
3. INFO,
4. WARNING,
5. ERROR and
#include <android/log.h>
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Message");
The Log class defines one character long methods for each sever-
ity except ASSERT. Therefore, VERBOSE messages can be logged using
Log#v, DEBUG messages using Log#d and so on. The Log class also de-
fines a jokingly named method Log#wtf (literally What a Terrible Failure;
reports a condition that should never happen) that logs with severity
ASSERT.
The Android logging API is also available from native code upon
including the log.h header file (see Source code 9).
64
4. Implementation
The Crash Reporting Library uses the CrashLogger static class located
in the com.avg.zaap.crashlibrary.core.logger package as an en-
try point for all of its logging functionality. The CrashLogger class
is initialised during the Crash Reporting Library initialisation within
the CrashLib#init method call. CrashLogger automatically loads the
logger instance configured in the library configuration (see Subsec-
tion 4.7.6).
The CrashLogger API mirrors the API defined in the Android
Log class, using the same one character long method naming pattern.
Additionally, its methods also support string formatting using op-
tional varargs arguments. The main advantage of such approach is
the effortless compatibility with overwhelming majority of Android
applications.
The default logger for the Crash Reporting Library is implemented in
the com.avg.zaap.crashlibrary.core.logger.DefaultLogger class.
65
4. Implementation
The default logger logs messages only when used in the debug build of
the Crash Reporting Library (see Section 4.13). When using the release
build of the Crash Reporting Library, the default logger silently discards
all logging method calls.
The standalone BinUnPacker API uses a custom logger im-
plemented in the JavaSystemLogger located in the com.avg.zaap.
crashlibrary.core.logger package. The JavaSystemLogger prints
log messages with severity ERROR or ASSERT to the standard error out-
put. Messages with lower severity are printed to the standard output.
An application developer may also define its own logger by im-
plementing the com.avg.zaap.crashlibrary.core.logger.ILogger
interface and setting the implementation class in the configuration
management (see Subsection 4.7.6).
4.12 Testing
This section defines the testing strategy used to verify the Crash Re-
porting Library builds.
The testing strategy for the Crash Reporting Library involves unit
testing, integration testing and integration with the existing build and
automation infrastructure at AVG.
66
4. Implementation
package com.example;
import android.content.Context;
67
4. Implementation
68
4. Implementation
package com.example;
import android.content.Context;
@Before
public void setUp() {
mContext = mock(Context.class);
mDependency = mock(Dependency.class);
mExample = new Example(mContext, new
IExampleFactory {
@Override
public void Dependency getDependency() {
return mDependency;
}
});
}
@Test
public void example_emptyString_returnsTrue() {
assertThat(mExample.example(""), is(true));
}
@Test
public void example_nonEmptyString_returnsFalse() {
assertThat(mExample.example("test"), is(false));
}
}
69
4. Implementation
def example_step_function(params):
logger.debug("[{0}, {1}]".format(params["first"],
params["second"])
execution.passed()
70
4. Implementation
• autolib,
• TSDs.
CrashDialogDebug.tsd
This TSD tests the DIALOG configuration value of the
showErrorType configuration option for the debug build of the
Crash Reporting Library.
CrashDialogRelease.tsd
This TSD tests the DIALOG configuration value of the
showErrorType configuration option for the release build of
the Crash Reporting Library.
CrashErrorScreenDebug.tsd
This TSD tests the ERROR_SCREEN configuration value of the
71
4. Implementation
CrashErrorScreenRelease.tsd
This TSD tests the ERROR_SCREEN configuration value of the
showErrorType configuration option for the release build of
the Crash Reporting Library.
CrashNoneDebug.tsd
This TSD tests the NONE configuration value of the
showErrorType configuration option for the debug build
of the Crash Reporting Library.
CrasNoneRelease.tsd
This TSD tests the NONE configuration value of the
showErrorType configuration option for the release build of
the Crash Reporting Library.
CrashNotificationDebug.tsd
This TSD tests the NOTIFICATION configuration value of the
showErrorType configuration option for the debug build of the
Crash Reporting Library.
CrashNotificationRelease.tsd
This TSD tests the NOTIFICATION configuration value of the
showErrorType configuration option for the release build of
the Crash Reporting Library.
CrashToastDebug.tsd
This TSD tests the TOAST configuration value of the
showErrorType configuration option for the debug build
of the Crash Reporting Library.
CrashToastRelease.tsd
This TSD tests the TOAST configuration value of the
showErrorType configuration option for the release build of
the Crash Reporting Library.
CrashReportAll.tsd
This TSD tests the ALL publishing strategy using both CAP
72
4. Implementation
73
4. Implementation
/delete?guid=value (GET)
Deletes the crash report file previously uploaded with the given
GUID value.
/disable-server (GET)
Disables the mock server. When disabled, the mock CAP Server
always return -1 error as its response.
/enable-server (GET)
Enables the mock server if the mock server has been previously
disabled.
/uploading (GET)
Returns whether there is a file currently being uploaded to the
mock CAP Server.
4.12.4 Automation
74
4. Implementation
4.13 Building
This subsection describes the building process of the Crash Reporting
Library and its respective variants.
The Crash Reporting Library solutions is divided into the following
three Gradle submodules:
75
4. Implementation
76
4. Implementation
activityRelease
This configuration uses the release version of the Crash Report-
ing Library and configures the ERROR_SCREEN as its showError
configuration value.
dialogDebug
This configuration uses the debug version of the Crash Reporting
Library and configures the DIALOG as its showError configura-
tion value.
dialogRelease
This configuration uses the release version of the Crash Re-
porting Library and configures the DIALOG as its showError con-
figuration value.
noneDebug
This configuration uses the debug version of the Crash Reporting
Library and configures the NONE as its showError configuration
value.
noneRelease
This configuration uses the release version of the Crash Re-
porting Library and configures the NONE as its showError config-
uration value.
notificationDebug
This configuration uses the debug version of the Crash Report-
ing Library and configures the NOTIFICATION as its showError
configuration value.
notificationRelease
This configuration uses the release version of the Crash Report-
ing Library and configures the NOTIFICATION as its showError
configuration value.
toastDebug
This configuration uses the debug version of the Crash Reporting
Library and configures the TOAST as its showError configuration
value.
77
4. Implementation
toastRelease
This configuration uses the release version of the Crash Re-
porting Library and configures the TOAST as its showError con-
figuration value.
reportAnyBrokenSDDebug
This configuration uses the debug version of the Crash Reporting
Library. It configures the library to use the ANY publishing strat-
egy and adds the BrokenSDCardPublisher in the configuration
management.
reportAnyBrokenSDRelease
This configuration uses the release version of the Crash Report-
ing Library. It configures the library to use the ANY publishing
strategy in the configuration management.
reportAnyDebug
This configuration uses the debug version of the Crash Report-
ing Library. It configures the library to use the ANY publishing
strategy in the configuration management.
reportAnyRelease
This configuration uses the release version of the Crash Report-
ing Library. It configures the library to use the ANY publishing
strategy in the configuration management.
reportBestEffortDebug
This configuration uses the debug version of the Crash Report-
ing Library. It configures the library to use the BEST_EFFORT
publishing strategy in the configuration management.
reportBestEffortRelease
This configuration uses the release version of the Crash Re-
porting Library. It configures the library to use the BEST_EFFORT
publishing strategy in the configuration management.
78
4. Implementation
The mock CAP server offers the two build configurations automat-
ically created by Android Studio: debug and release. Both of these
configurations are identical.
buildCrashLibraryDebug
Builds the debug version of the Crash Reporting Library, all
debug configurations of the Simulator application and the mock
CAP server.
buildCrashLibraryRelease
Builds the release version of the Crash Reporting Library, all
release configurations of the Simulator application and the
mock CAP server.
buildCrashLibrary
Builds both versions of the Crash Reporting Library, all
build configurations of the Simulator application and the
mock CAP server. Depends on buildCrashLibraryDebug and
buildCrashLibraryRelease. This task is executed by Final-CI.
testCrashLibraryDebug
Runs JUnit tests for the debug version of the Crash Reporting
Library. Depends on buildCrashLibraryDebug.
testCrashLibraryRelease
Runs JUnit tests for the release version of the Crash Reporting
Library. Depends on buildCrashLibraryRelease.
testCrashLibrary
Runs JUnit tests for the all versions of the Crash Reporting Li-
brary. Depends on buildCrashLibrary.
79
4. Implementation
copyTestResults
Copies the JUnit tests results into the output folder observed by
Final-CI. Depends on buildCrashLibrary. This task is executed
by Final-CI.
4.14 Publishing
This section describes the artefact publishing process of the Crash
Reporting Library.
The common way of distributing Android libraries is the Android
Archive format, usually denoted by the .aar file extension. The format
itself is identical to standard Java .jar archive however, the .aar file
extension signalises that the library contains compiled classes in the
Dalvik Executable Format and is therefore incompatible with standard
Java Virtual Machine.
Therefore, Android libraries can be distributed in the same way as
their Java counterparts, using the same tools. Gradle provides com-
patibility with Maven and its POM (Project Object Model) [61].
AVG uses JFrog’s Artifactory [62], a universal repository manager
that supports Java, JavaScript, PHP, Python and Ruby libraries amongst
others. An artefact can be published using either the web interface
(see Figure 4.21) or using the Gradle Plug-in.
The Crash Reporting Library uses the JFrog Artifactory Plug-in (de-
pendency com.jfrog.artifactory) for direct publishing into Artifac-
80
4. Implementation
tory. Gradle optionally uses Java Properties File Format for configura-
tion. Gradle automatically loads the gradle.properties files located
in home Gradle directory (%USERPROFILE%\.gradle on Windows or
~/.gradle on UNIX-based systems), in the main project directory
and in the submodule directory. This allows storing the Artifactory
credentials outside the actual project.
The Crash Reporting Library defines a custom Gradle task
named artifactoryPublish for publishing the library. The
artifactoryPublish task requires the following Gradle properties to
configured in one of the gradle.properties files:
• artifactory_contextUrl,
• artifactory_user and
• artifactory_password
81
5 Conclusion
This thesis successfully fulfilled its outlined goals. A comparative
research and analysis of the crash reporting solutions available for
Android was performed. Since none of the considered solutions pro-
vided the desired level of universality and configurability, a custom
solution named Crash Reporting Library was implemented.
The implemented solution offers crash reporting of both managed
code and native code crashes, as requested. It does so using a unified
API. The solution collects the metadata required by the existing infras-
tructure and allows processing crashes of Android applications in the
same way as AVG’s portfolio of existing desktop applications does.
The developed solution offers extensive and easily maintainable
configuration management and due to its modular architecture, it
offers multiple ways of notifying the user amongst others. The con-
figuration management of the implemented solution offers various
extension points in order to allow easy implementation of application-
specific extensions.
The implemented architecture was documented using the Unified
Modelling Language. The source code was thoroughly documented
using the JavaDoc documenting syntax.
The Crash Reporting Library comes with a basic predefined sets of
providers and publishers, shortening the time necessary for setting up
a commonly used configuration.
A custom light-weight file format was developed in order to lower
the computation power needed for collecting and publishing crash
reports. A set of support tools for this file format was developed in
cooperation with the Quality Assurance Team in order to best suit
their needs.
Based on my proposal, the implemented solution offers advanced
connection handling, eliminating undesired data transfers on limited,
unstable and metered networks.
A detailed and comprehensive test strategy including unit tests,
integration tests and automation was designed and implemented
using the standard tools used by AVG. The build and verification
process is fully integrated into AVG’s infrastructure.
83
5. Conclusion
84
Bibliography
1. ORACLE CORPORATION. Java Platform SE 7: NullPointerException.
2016. Available online [last revision 12 December 2017]
https : / / docs . oracle . com / javase / 7 / docs / api / java / lang /
NullPointerException.html.
2. XAMARIN, INC. Xamarin: Xamarin.Android. 2017. Available online
[last revision 12 December 2017]
https://developer.xamarin.com/api/root/MonoAndroid-lib/.
3. MEYER, K. Ruboto. 2017. Available online [last revision 12 December
2017]
https://web.archive.org/web/20161119184120/http://ruboto.
org:80/.
4. PROGRESS SOFTWARE CORPORATION. NativeScript: Home. 2017.
Available online [last revision 12 December 2017]
https://www.nativescript.org/.
5. JETBRAINS. Kotlin Programming Language. 2017. Available online [last
revision 12 December 2017]
https://kotlinlang.org/.
6. GOOGLE. Android Developers: WebView. 2017. Available online [last
revision 12 December 2017]
https://developer.android.com/reference/android/webkit/
WebView.html.
7. THE APACHE SOFTWARE FOUNDATION. Apache Harmony: Open
Source Java Platform. 2017. Available online [last revision 12 Decem-
ber 2017]
https://harmony.apache.org/.
8. ORACLE CORPORATION. OpenJDK. 2017. Available online [last revi-
sion 12 December 2017]
http://openjdk.java.net/.
9. MURPHY, M. L. The CommonsBlog: Musings on Android and the Open-
JDK. 2016. Available online [last revision 12 December 2017]
https://commonsware.com/blog/2016/01/07/musings-android-
openjdk.html.
85
BIBLIOGRAPHY
10. NORBYE, T. Android Studio Project Site: Android Studio 0.3.2 Released.
2013. Available online [last revision 12 December 2017]
http://tools.android.com/recent/androidstudio032released.
11. GOOGLE. Android Developers: Use Java 8 Language Features. 2017. Avail-
able online [last revision 12 December 2017]
https : / / developer . android . com / guide / platform / j8 - jack .
html.
12. LAU, J. Android Developers: Future of Java 8 Language Feature. 2017.
Available online [last revision 12 December 2017]
https : / / android - developers . googleblog . com / 2017 / 03 /
future-of-java-8-language-feature.html.
13. MEDNIEKS, Z.; DORNIN, L.; MEIKE, G. B.; NAKAMURA, M. Pro-
gramming Android, Second Edition. Sebastopol, California: O’Reilly
Media, 2012.
14. PYTHON SOFTWARE FOUNDATION. Python.org: About Python. 2017.
Available online [last revision 12 December 2017]
https://www.python.org/about/.
15. FREE SOFTWARE FOUNDATION. GNU Project: Free Software Foun-
dation: Bash. 2017. Available online [last revision 12 December 2017]
https://www.gnu.org/software/bash/.
16. GOOGLE. Android Studio: The Official IDE for Android. 2017. Available
online [last revision 12 December 2017]
https://developer.android.com/studio/index.html.
17. CHENG, B.; BUZBEE, B. A JIT Compiler for Android’s Dalvik VM. 2010.
Available online [last revision 12 December 2017]
https : / / dl . google . com / googleio / 2010 / android - jit -
compiler-androids-dalvik-vm.pdf.
18. GOOGLE. Android Developers: Android NDK. 2017. Available online
[last revision 12 December 2017]
https://developer.android.com/ndk/index.html.
19. ECMA INTERNATIONAL. Introducing JSON. 2017. Available online
[last revision 12 December 2017]
http://www.json.org/.
86
BIBLIOGRAPHY
87
BIBLIOGRAPHY
88
BIBLIOGRAPHY
40. PARET, R. Fabric is Joining Google. 2017. Available online [last revision
12 December 2017]
https://fabric.io/blog/fabric-joins-google.
41. PEREZ, S. Twitter’s Mobile Crash Reporting Tool Crashlytics Arrives On
Android. 2013. Available online [last revision 12 December 2017]
https://techcrunch.com/2013/05/30/twitters-mobile-crash-
reporting-tool-crashlytics-arrives-on-android/.
42. FABRIC. Fabric for Android: Build Tools. 2017. Available online [last
revision 12 December 2017]
https://docs.fabric.io/android/crashlytics/build- tools.
html.
43. GOOGLE. Android Developers: Service. 2014. Available online [last re-
vision 12 December 2017]
https : / / developer . android . com / guide / topics / manifest /
service-element.html.
44. ORACLE CORPORATION. Java Platform SE 7: Throwable. 2016. Avail-
able online [last revision 12 December 2017]
https : / / docs . oracle . com / javase / 7 / docs / api / java / lang /
Throwable.html.
45. ORACLE CORPORATION. Java Platform SE 7: Error. 2016. Available
online [last revision 12 December 2017]
https : / / docs . oracle . com / javase / 7 / docs / api / java / lang /
Error.html.
46. ORACLE CORPORATION. Java SE Documentation: JNI Functions. 2014.
Available online [last revision 12 December 2017]
http://docs.oracle.com/javase/7/docs/technotes/guides/
jni/spec/functions.html.
47. GOOGLE. Create Hello-CMake with Android Studio. 2017. Available on-
line [last revision 12 December 2017]
https://codelabs.developers.google.com/codelabs/android-
studio-cmake/#0.
48. ORACLE CORPORATION. Java Platform SE 7: System. 2017. Available
online [last revision 12 December 2017]
https : / / docs . oracle . com / javase / 7 / docs / api / java / lang /
System.html.
89
BIBLIOGRAPHY
90
BIBLIOGRAPHY
58. GOOGLE. Android Developers: Log. 2017. Available online [last revision
12 December 2017]
https://developer.android.com/reference/android/util/Log.
html.
59. HAMCREST.ORG. Java Hamcrest. 2012. Available online [last revision
12 December 2017]
http://hamcrest.org/JavaHamcrest/.
60. GOOGLE. Android Developers: UI Automator. 2017. Available online
[last revision 12 December 2017]
https : / / developer . android . com / training / testing / ui -
automator.html.
61. THE APACHE SOFTWARE FOUNDATION. Maven: POM Reference.
2017. Available online [last revision 12 December 2017]
https://maven.apache.org/pom.html.
62. JFROG. Android Developers: UI Automator. 2017. Available online [last
revision 12 December 2017]
https://www.jfrog.com/artifactory/.
91