Asynchronizer: a tool for retrofitting concurrency into Android apps

Problem Description

Running compute-intensive or blocking I/O operations in the UI event thread of smartphone apps can severely degrade responsiveness. Despite the fact that Android supports writing concurrent code via AsyncTask, we know little about how developers use AsyncTask to improve responsiveness. To understand how AsyncTask is used/underused/misused in practice, we first conduct a formative study using a corpus of 104 open-source Android apps comprising 1.34M SLOC. Our study shows that even though half of the apps use AsyncTask, there are hundreds of places where they missed opportunities to encapsulate long-running operations in AsyncTask. Second, 46% of the usages are manually refactored. However, the refactored code contains concurrency bugs (such as data races) and performance bugs (concurrent code still executes sequentially).

Inspired by these findings, we designed, developed, and evaluated Asynchronizer, an automated refactoring tool that enables developers to extract long-running operations into AsyncTask. Asynchronizer uses a points-to static analysis to determine the safety of the transformation. Our empirical evaluation shows that Asynchronizer is (i) highly applicable, (ii) accurate, (iii) safer than manual refactoring (iv) it saves development effort, (v) its results have been accepted by the open-source developers. This shows that Asynchronizer is useful.

Publications

Retrofitting Concurrency for Android Applications through Refactoring

By Yu Lin, Cosmin Radoi, Danny Dig.
22th ACM SIGSOFT International Symposium on the Foundations of Software Engineering
(FSE 2014), Hong Kong, China, Nov.. 2014

Instructions and Screenshots

Asynchronizer is implemented as an Eclipse plugin that extends Eclipse's refactoring engine. It contains two parts: refactoring and data race checking.

Code Transformation

To refactor code by Asynchronizer, the programmer selects the code to be moved into AsyncTask and then from pop-up menu, selects Concurrency RefacotoringsConvert to AsyncTask. Asynchronizer 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 Asynchronizer analyzes and rewrites the code. If the programmer asked for a preview then Asynchronizer 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 Asynchronizer apply all changes. Before applying any transformations, Asynchronizer checks that the input program meets the refactoring preconditions. Asynchronizer reports to the programmer any preconditions that are not met and prevent the transformation.

Below is a screenshot from Convert to AsyncTask refactoring:

extracting code into an AsyncTask


In this refactoring, Asynchronizer performs the following transformations:

Checking Races

After the refactoring, Asynchronizer helps programmer check races introduced by the refactoring. To check the data races, programmer first selects the task object and then click Concurrency RefacotoringsCheck Data Races in the pop-up menu. Asynchronizer reports races and their locations in the console of Eclipse. Note that programmer should perform refactoring first then check data races.

Below is a screenshot from Check Data Races:

checking data races because of AsyncTask refactoring

Tool Demo

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

Download and Install

Asynchronizer 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 into your Eclipse installation directory, under the plugins directory, then restart Eclipse. On the other hand, you should set an environment variable ANDROID_PATH that points to android.jar. For example, set ANDROID_PATH to ~/android-sdk/platforms/android-19/android.jar. Here is the source code.

Study on Usage of AsyncTask

We studied the use, misuse and underuse of AsyncTask. We analyzed 104 Android apps on Github. The repository names are listed here.

Use

To understand how AsyncTask is used, 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

Note that git_project_path is the absolute path to your local git repository. Our analyzer will create two sub-directores "before" and "after" under "git_project_path". "before" contains the code that does not use AsyncTask, while "after" contains the code which uses AsyncTask in the immediate subsequent version. By comparing the two versions, we can understand how developers introduce and use AsyncTask. git_project_path/before/metadata.txt contains the file path and SHA1 value of the two versions.

Misuse

We found two kinds of misuse:
(i) access unthread-safe GUI widgets in doInBackground method (see this table)
(ii) invoke blocking method get immediately after starting the task (see this table)

Underuse

We manually identified potential long-running operations that execute in the UI event thread in 51 projects. We show these projects and the invocation of potential long-running operations in this table.

Experimental Evaluation

We ran Asynchronizer on 62 classes from 13 open-source Android projects, in which developers manully refactored the sequential code into concurrect code via AsyncTask. We applied Asynchronizer to 77 places in these projects and compared our refactoring with developers' maunal refactoring. The following table shows the projects, classes and their corresponding versions:

Project Class Version
libreliodev-android DownloadedMagazinesListView.java 1cb608826b928ae0fa3f27bca64c32df4cd26b26
MagazineAdapter.java 1cb608826b928ae0fa3f27bca64c32df4cd26b26
MuPDFActivity.java 4f2807789b0dcc96893ff814674043d3b4f65684
SlideshowAdapter.java dee24a098488cbae024fa019405139dab9527715
StartupActivity.java 4f2807789b0dcc96893ff814674043d3b4f65684
piusvelte-sonet About.java a9288678f5a9264385fcc52ed7b803695ef3c890
OAuthLogin.java a9288678f5a9264385fcc52ed7b803695ef3c890
SonetComments.java 2b0ef3c876d327e0215feb895852c258867e040f
SonetService.java b5f9bc6e0dc49defb06e52a9e9dcafdd8643649e
socialize-sdk-android AuthenticateActivity.java e60990c75fead40232fd6e6da092709286264635
FacebookDialogListener.java c8d0ce547ca41d605fd8a4e415bb75b45c77eae1
SampleActivity.java 1fbf628591239608d67132b34abd98f78dc97ddd
SocializeLaunchActivity.java 3383019afc34d138f2dc1e1ee91cf0de8c7e3275
ChatSecureAndroid MessageView.java 341666ff3a5de5bcfb7341e131bad4a85c4ae149
NewChatActivity.java d0ea328ee0fdc280c560b54ce4ac4d8e522a16c9
ProviderListItem f6648aeba5ca3aef23ce8bd625e102723ef223c9
Gwindow-WhatAndroid DownloadDialog.java 145f2af3b173bf32adb456ebcdd6d758a5a95d74
NewConversationActivity.java 8db8242fe998d4a99e51e441f12abf6c842b49d5
NewThreadActivity.java 8db8242fe998d4a99e51e441f12abf6c842b49d5
PostOptionsActivity.java 8db8242fe998d4a99e51e441f12abf6c842b49d5
irccloud-android BuffersListFragment.java 7c601d7940ab633624706ea705e0558c44a07856
MessageActivity.java 3ee054f89a4d0b2af1bde69bd68651ac56ef2b49
MessageViewFragment.java 7c601d7940ab633624706ea705e0558c44a07856
cyclestreets-android ApiClient.java 9189f987ef4b4a1ff888fca7eb09033b0b9b4e49
ItineraryActivity.java 912850c4d1e7f8ff739ee10127b656d575dded3f
PhotomapListener.java 912850c4d1e7f8ff739ee10127b656d575dded3f
owncloud-android AuthenticatorActivity.java 8f0128cbab3127d64493beb7ba8c817fabc2e1b5
FileDetailFragment.java 1dbc69dc1187de479ffee29bc134381e306a7fc7
TestActivity.java 8e0d41cca90a255a8c32ea8ee4cb8da626e62331
android_apps_Settings AppRestrictionsFragment.java d4abdd27adac36e7243bcaae37a7a2c69ac73db7
CryptKeeper.java e18897bc2242110782fca135e9e47fcdb5839d64
DataUsageSummary.java 8e911d7b1a6817f67480b7677f8d36ab3bfb00f2
SettingsAppWidgetProvider.java 6e74d41bd0525459c43ed010e8f049ffc20ca362
android_apps_Calendar AlertActivity.java 20882e2147cc737fb35d09dfd3ce74c25968b21e
CalendarController.java 0558defd2215696cee0768ce2bf2cb4da56efc42
GlobalDismissManager.java a191a694a075e1f2ee8b2755e9fe379194529f9c
Utils.java 1d564f63f731565219aaca9e1b7e5f466b143c71
mtotschnig-MyExpenses MyPreferenceActivity.java 4857571fa2c6083770fdc8ef929f69edbbec9159
Utils.java b52b4449a7c90ee379258f693ccd9c0424314db8
allplayers-android AlbumAdapter.java e382596e1202715a06ac8cea41712968d32dc3c1
AlbumPhotosActivity.java 4ff7fc9581ed204f5c5e2678d4ecfebd14482fbb
EventsActivity.java f193d5d4af020a1b426abdeba533dcc951e0fe80
GroupAlbumsActivity.java 9f54e44320d1be365f2c50059e1e3d1f1d89a1c8
GroupEventsActivity.java e148e6fdfcfd62793f2b47d680af6b65324c1f4d
GroupMembersActivity.java c4a1d514c82ae892bcda001a9f763f744ffb8b25
GroupPageActivity.java d1cbaddd78ebb9a9e9f1fdff779790c0032ddc9c
Login.java e5357d456f6de6b12a60b8a64fc2a2961c55ab20
MainScreen.java f71bf6ff5fe242f12f0deaaa3706a04a6884af7f
MessageActivity.java b7f0adc5bb32a01ecc6778e00a67e5d8a7dd3c9f
MessageInbox.java f3353af004f74aba5cf6a1e1809f2d46188dbb47
MessageReply.java 082291d9c862f1a3783f79ddb04976be02e62433
MessageSent.java 1e5b6c4c64ac67bcf1f7179e6168cba573d44577
MessageThread.java 4e7fc2e9f2918b3c4b06a2b15a04242be314945c
PhotoAdapter.java 2195c2bcd24be10eb67fe4e514a8e5c652c810f1
PhotosActivity.java 04d7565067740d0e8e4b44419916ac60873835a4
PhotoDisplayActivity.java 5cae12bb80950edbc22c0e4c0f0cc2fcff5bdf31
SearchGroupsListActivity.java f1b0ff3fed4fc865445375752db5390d2b13fa6d
GRTransit BusroutesActivity.java 770bd8e3c24ed57f92d06375a10c02c5414f0703
BusstopsActivity.java 69398bd7f4cb83bf11f1f0f11d47cd2b969df01f
RouteselectActivity.java e4e3abc24e39fd3cc9a50c8e8960b74bf2f5925a
SearchStopsActivity.java 0710d31928c4c4dbdce7428c698a23a12be896a7
TimesActivity.java 0ee71d82126a32f8f08dfd1789f86f3d2cb37cfe

Asynchronizer found 24 unfixed races in four projects during developers' manual refactorings. We reported these races to the developers. The following table shows our bug reports:

Project # of Races Bug Report
ChatSecureAndroid 7 Issue 410
Irccloud-Android 3 Issue 60
piusvelte-sonet 12 Issue 1
GRTransit 2 Issue 10

We also applied our refactoring to six projects that do not have manual AsyncTask refactoring. These projects execute long operations such as database access, decoding bitmaps in UI thread. We moved these operations into AsyncTask through Asynchronizer. The following table shows these projects and the refactored classes:

Project Class Version
Connectbot PubkeyListActivity.java fb1d457d31686b8c78aede8817eca65084715ed0
TerminalKeyListener.java
HostListActivity.java
HostEditorActivity.java
TerminalManager.java
FBReaderJ ImageViewActivity.java 24d3813d5b7169e995dbe389e5ea577b2f652e86
ZLAndroidPaintContext.java
BookInfoActivity.java
NetworkBookInfoActivity.java
LibraryActivity.java
K-9 AttachmentView.java 92e9e6d140dcc81bfd669a48805bc900be2f08f2
MessageCompose.java
MessageViewFragment.java
ChooseFolder.java
AccountSetupBasics.java
keepassdroid FileSelectActivity.java d90a34ba55380c6c4534e86731ef393f4583c2a8
PasswordActivity.java
vudroid ZoomRoll.java r56
vlc-android BrowserAdapter.java c50ea3b3b8d8e063f2824b5fcac6d73c7fd93bb2
PreferencesActivity.java
SearchFragment.java
AudioBrowserListAdapter.java
CoverMediaSwitcher.java
VideoListAdapter.java
VideoPlayerActivity.java
VLCApplication.java

We submitted these refactorings to developers as potential improvements. The following table shows our reports and pathces:

Project # of Refactorings Race Fixes Reports/Patches
connectbot 24 70 Issue 29
FBReaderJ 10 8 Issue 185
KeePassDroid 3 0 Issue 43
K-9 7 38 Issue 450
vudroid 1 13 Issue 125
VLC 13 16 Issue 10829
cgeo 11 0 Issue 4428
andlytics 2 0 Issue 651
rpicheck 13 0 Issue 63
adblockplusandroid 1 0 Issue 6

Team

Feedback

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