AsyncDroid: a tool for Converting Basic Async Constructs to Enhanced Async Constructs for Android apps

Problem Description

Unless app developers resort to asynchronous programming, their apps are unresponsive. Android provides several async constructs that developers can use. However, developers can still use the wrong async constructs, which result in memory leaks, lost results, and wasted energy. Fortunately, refactoring tools can eliminate these problems by transforming async code to use the appropriate constructs.

In this work we conducted a formative study on a corpus of 611 widely-used Android apps to map the asynchronous landscape of Android apps, understand how developers retrofit asynchrony, and learn about barriers encountered by developers. Based on this study, we designed, implemented, and evaluated AsyncDroid, a refactoring tool which enables Android developers to transform existing improperly-used async constructs into correct constructs. Our empirical evaluation shows that AsyncDroid is applicable, accurate, and saves developers effort. We submitted 30 refactoring patches, and developers think our AsyncDroid is useful.

Publications

Study and Refactoring of Android Asynchronous Programming

By Yu Lin, Semih Okur, Danny Dig.
30th IEEE/ACM International Conference on Automated Software Engineering
(ASE 2015), Lincoln, Nebraska, Nov. 2015

Refactorings for Android Asynchronous Programming

By Yu Lin, Danny Dig.
30th IEEE/ACM International Conference on Automated Software Engineering
(ASE 2015), Tool Demo Session, Lincoln, Nebraska, Nov. 2015

Instructions and Screenshots

Improperly used AsyncTask can lead to memory leaks, losing task results and wasting energy when GUI recreation occurs during task running (see this blog). AsyncDroid is implemented as an Eclipse plugin that extends Eclipse's refactoring engine. It transforms AsyncTask into IntentService to avoid the above problem for long-running tasks.

Code Transformation

To refactor code by AsyncDroid, the programmer selects the doInBackground method of the tagert AsyncTask, and then from pop-up menu, selects AndroidAsyncRefactoringConvert to IntentService. AsyncDroid will then present three choices: perform and apply the refactoring (no preview), perform the refactoring and show a preview, or cancel the refactoring. If the programmer selects to perform the refactoring then AsyncDroid analyzes and rewrites the code. If the programmer asked for a preview then AsyncDroid shows the changes in a before-and-after pane (see the screenshot below). In this pane the programmer can further select that only a subset of the changes be applied, or let AsyncDroid apply all changes. Before applying any transformations, AsyncDroid checks that the input program meets the refactoring preconditions. AsyncDroid reports to the programmer any preconditions that are not met and prevent the transformation.

Below is a screenshot from Convert to IntentService refactoring:

Convert AsyncTask to IntentService


In this refactoring, AsyncDroid performs the following transformations:

Tool Demo

We provide a video for demo (this demo includes both asynchronizer and asyncdroid):

Download and Install

AsyncDroid is released under the Eclipse Public License. It requires that you use Eclipse (version >= 4.2, Juno with jre >= 1.7). Once you have installed Eclipse, copy this jar file (source code is included) into your Eclipse installation directory, under the plugins directory, then restart Eclipse.

Study on Android Asynchronous Programming

We studied the popularity of three Android async constructs: AsyncTask, IntentService and AsyncTaskLoader. We also analyzed how developers introduce the three constructs when they first use them. Finally, we survey 10 StackOverflow experts for their opinions on Android async constructs.

Popularity of Android async constructs

To understand the popularity, we downloaded 500 most popular Android apps from Github. Here is the app list. We analyze the popularity by counting the number of instances for each construct in these 500 projects. The algorithm traverses the AST. The source code for counting constructs is in this repository. The result of the popularity is here.

How are Android async constructs introduced

To understand how developers introduce IntentService, we use 93 Android apps that use both AsyncTask and IntentService from Github. Here is the app list.

To understand how developers introduce AsyncTaskLoader, we use 18 Android apps that use both AsyncTask and AsyncTaskLoader from Github. Here is the app list.

To understand how a construct is introduced at the first time in a project, first download the github projects you want to analyze, and our analyzer search_async.jar. Then execute

java -cp search_async.jar study.SearchAsyncCommit git_project_path construct_name

Note that git_project_path is the absolute path to your local git repository, while construct_name is the name of the construct (e.g., IntentService). The analyzer will create two sub-directores "before-async" and "after-async" under "git_project_path". "before-async" includes files that do not contain the given construct name, while "after-async" includes files that contain the given construct name in the immediate subsequent version. By comparing the two versions, we can understand how developers introduce and use the construct. git_project_path/before-async/metadata.txt contains the file path and SHA1 value of the two versions.

We also found two kinds of misuses for IntentService (see this table):

(i) Do not provide service name when invoking startService.
(ii) Executing AsyncTask in onHandleIntent, which is unnecessary.

Survey on Android Expert Developers

Based on the study result, we ask three questions to 10 Android expert developers that we found on StackOverflow. We got 5 replies. The questions and their answers can be found here.

Experimental Evaluation

We ran AsyncDroid on 97 AsyncTasks from 9 open-source Android projects. These projects use AsyncTasks a lot but seldom use IntentService. This table shows the projects, classes, lines where the refactoredAsyncTask locates, and their corresponding versions.

We submitted 45 refactorings in 7 projects to developers as potential improvements. The following table shows our reports and pathces:

Project # of Refactorings Reports/Patches
owncloud-android 3 PR 969
OpenTripPlanner-android 3 PR 472
prey-android-client 7 PR 90
AntennaPod 8 PR 793
Gwindow-WhatAndroid 9 PR 34
UltimateAndroid 6 PR 10
TextSecure 9 PR 3299

Integrate with Google ShipShape

We also integrated AsyncDroid with Google static analysis platform, ShipShape. ShipShape can run with docker images that are pulled from Docker Hub or local docker images.

Notice that ShipShape runs AsyncDroid as an Eclipse plugin in Eclipse headless mode (here is the source code of the headless plugin), so the input directory must be an Eclipse project (>=Eclipse 4.4.2, Luna), i.e., the dir must contain .project file.

Create Dependencies for the Analyzed Project

This step is required and it's used to collect the dependent jars for the project.

Run with Docker Hub image

Build and run with local docker image

Run examples and end to end test:

The source code dir contains an example in dir AsyncRefactoring_analyzer/testdata/open311/open311-android. You can use this dir as input dir to try out the plugin.

To run end to end test: first move the source code into the ShipShape repo as described above, then run $ ./shipshape/AsyncRefactoring_analyzer/test/end_to_end_test.sh --tag local. The output log is in AsyncDroid_end_to_end_test.log

Team

Feedback

If you found AsyncDroid useful, we would love to hear from you. Please send constructive feedback to Yu Lin.