Automated Program Repair of UI-centric Android Bugs
How Far are We?
JW
Junayed Mahmud · Sparsh Pandey · Nadeeshan De Silva · Atish Kumar Dipongkor · Jingjing Wu Oscar Chaparro · Mattia Fazzini · Kevin Moran
Fifteen years of automated program repair
APR has been evaluated almost entirely on library code.
Success has been largely dictated by unit tests.
Effectiveness on UI-centric programs?
The UI is nearly half of user-facing software: half the code, half the time, half the maintenance.
Myers, CHI 1992
11:49▾ ◢ ▮
Thorrez · 2 hrs
[2024] And it looks like this is the draft, and it was published on the author's blog here: https://telefoncek.si/2024/05/2024-05-30-grapheneos-and-fore…
azalemeth · 1 hr
I really love GrapheneOS but I _wish_ there was a version in which you could get a root shell and extract private data of apps you install when verified as the user. The developers are on record as saying that root blows a hole in their security model (it does!) but if there was _some_ way of doing it safely, so I can modify applications I as the user wish to, it would be my ideal OS.
djrj477dhsnv · 47 mins
I wish this as well. I make a userdebug build myself to get adb root, which isn't difficult, but would be a lot nicer if it were officially supported.
lmiric · 23 mins
That's interesting. Can you share a guide for doing that?
subscribed · 1 hr
You can't have a cake and eat it. A root access is a big hole, there's no way mainline will support it.
Event listenersCode the framework calls on a tap or a long press
StateValues the screen keeps between events
LifecycleCallbacks when the screen is paused, destroyed, re-created
11:49▾ ◢ ▮
Thorrez · 2 hrs
[2024] And it looks like this is the draft, and it was published on the author's blog here: https://telefoncek.si/2024/05/2024-05-30-grapheneos-and-fore…
azalemeth · 1 hr
I really love GrapheneOS but I _wish_ there was a version in which you could get a root shell and extract private data of apps you install when verified as the user. The developers are on record as saying that root blows a hole in their security model (it does!) but if there was _some_ way of doing it safely, it would be my ideal OS.
djrj477dhsnv · 47 mins
I wish this as well. I make a userdebug build myself to get adb root, which isn't difficult, but would be a lot nicer if it were officially supported.
lmiric · 23 mins
That's interesting. Can you share a guide for doing that?
Five repair tools. Not one produced a patch that passed the tests.
·RewardRepair·NTR·D4C·ChatRepair·OpenHands
Part two
DroidFixBench
A benchmark for program repair of UI-centric Android bugs
Building DroidFixBench
What we need to evaluate UI-centric program repair
bug
Compilable snapshot
Statement-level localization
Correct patch
GUI tests
Bug description
How a real bug is built
Gathering real bugs
AndroR2+80 reportsour bug-localization dataset
F-Droid apps30 issuesfive recently updated apps
FBO4A22 reportsJohnson et al.
Harmonic HN · #114
1
Build the buggy commit
Gradle versions, dead dependencies. Many never build.
2
Reproduce on the emulator
✓
Pixel 2 · Android 9 · follow the report's steps.
3
Localize the fault
Diff buggy vs fixed commit. Two authors mark the statements.
4
Write two GUI tests
test 1 · fail → passtest 2 · fail → pass
Written by one author, reviewed by another.
5
Validate
✗ buggy✓ fixed
Both tests fail on the buggy build and pass on the fixed one.
0real bugs from 23 apps three sources, several person-months
12 crash25 output9 cosmetic4 navigation
Developer fix complexity
across the 50 bugs
Fixes in one method
27 bugs
Fixes across several methods
23 bugs
Lines added · removed
414 · 290 lines
Files changed
63 files
Largest single fix
92 lines
started
built
reproduced
selected
AndroR2+
80
42
35
35
Five F-Droid apps
30
23
21
13
FBO4A
22
–
–
2
Two GUI tests per bug, written by hand and checked by two authors.
Script114.java · UiAutomator · the bug-revealing test, as written
mDevice.swipe(500, 1600, 500, 800, 20); // scrollallStories.get(i).click(); // open the busiest storymDevice.swipe(540, y, 540, y, 100); // long press on the linkUiObject2 select = mDevice.wait( Until.findObject(By.text("Copy text")), 2000); // the context menu is upassertNotNull(select);
✕
✓
buggy build · the browser covers the menu · assertion fails
fixed build · the menu is found · passes
Both tests are fail-to-pass: each fails on the buggy build and passes on the fixed one. Test 1 reproduces the report directly; test 2 exercises the same behavior through the surrounding UI, so a patch has to fix the bug, not just the one path.
Emulator
Pixel 2 · Android 9
Time per test
≈ 2.5 min
Written by
one author, reviewed by another
Agreement
86% real · 98% synthetic
Synthetic bugs: Android mutants injected into real code.
new Handler().postDelayed(() -> { Intent targetActivity = new Intent(getApplicationContext(), MainPreferenceActivity.class); Intent targetActivity = null; targetActivity.putExtra("preference_fragment", whichFragment); startActivity(targetActivity);}, 250);
Description written from what we observed on the emulator
"Launch preference screen has stopped." Open the menu, tap Auto send, email and upload. Observed: the app crashes. Expected: the auto-send settings open.
46 bugs · 10 operators · 5 apps · every fix is one statement in one method
Ten patches, five different guessed ids: trainingTypeSlider, training_type_slider, trainingTypeSpinner…
OpenHands · methods that do not exist
String t = getTrainingTypeFromProgress(progress);activeSchedule.setTrainingType(t);appManager.getApplicationModel().saveSchedule(…);
cannot find symbol · build fails
A plausible-sounding API, invented on the spot.
D4C · a fix that does nothing
fab.setOnClickListener(v -> {saveTrainingScheduleInXml(); updateScheduleView(); });private void saveTrainingScheduleInXml() {// Logic to save training schedule state in XML file }
test fails
Two new methods, both empty.
NTR · FieldBook 1299 · an Activity that does not exist
0%plausible 445 of 600 patches build and pass all five tests
0%correct 82 of 600 match the developer's fix
356 of the 445 plausible patches are alternative fixes that two authors judged not to overfit. Scored against the developer's patch alone, agents get credit for one fix in five.
Harmonic #114 · twelve agent patches, one developer patch
app/
├─ build.gradle1
└─ src/main/java/
├─ com/simon/harmonichackernews/
│ ├─ CommentsFragment.javadeveloper
│ ├─ CommentsRecyclerViewAdapter.javadeveloper2 · Codex with localization
│ └─ UserDialogFragment.java1
└─ org/sufficientlysecure/htmltextview/ ← the HTML library bundled with the app
└─ LocalLinkMovementMethod.java10 · Claude ×4, Gemini ×4, Codex ×2
Claude · +Loc+Tests · LocalLinkMovementMethod.java
// GpsStatusFragment.updateFilterView()- if (filter.isEmpty()) {+ if (!GpsTestActivity.getInstance().mStarted+ || filter.isEmpty()) { filterGroup.setVisibility(View.GONE);
Stopping GNSS should clear the filter text. The agents cleared it from the fragment's own state, which the next status update sets again. The developer tied it to the Activity's flag.
Traditional tools failed on syntax. Agents fail on behavior.
One more one more thing
Sparsh Pandey
Undergraduate researcher, SAGE Lab, University of Central Florida. Co-author of this paper and of the agent follow-up study.
Applying to PhD programs in CS and SE this cycle.
If you are recruiting, come talk to him. He is standing right here. sparsh.pandey@ucf.edu
How far are we?
Paper
Slides
Replication package
Traditional repair fixes small UI bugs and fails on real ones, mostly on syntax it cannot see. Agents fix the syntax. What remains is scope, lifecycle, state, and deciding what correct means.