Skip to content

fix: move AIDL binder calls off main thread to prevent ANR (COLUMBA-3X)#524

Merged
torlando-tech merged 1 commit intomainfrom
fix/anr-rssi-polling
Feb 22, 2026
Merged

fix: move AIDL binder calls off main thread to prevent ANR (COLUMBA-3X)#524
torlando-tech merged 1 commit intomainfrom
fix/anr-rssi-polling

Conversation

@torlando-tech
Copy link
Copy Markdown
Owner

Summary

  • Wraps getRNodeRssi() and getInterfaceStats() AIDL binder IPC calls in withContext(Dispatchers.IO) to prevent background ANR when the service is slow (e.g. BLE hardware reads from RNode)
  • Fixes RNodeWizardViewModel.startRssiPolling() and InterfaceStatsViewModel.refreshStats() which both called synchronous AIDL on Dispatchers.Main
  • Sentry issue: COLUMBA-3X (Background ANR on Infinix X6716, Android 13, Columba 0.8.10-beta)
  • Cherry-picked from fix/anr-rssi-polling-v0.8.x

Test plan

  • ./gradlew :app:compileNoSentryDebugKotlin passes
  • ./gradlew :app:testNoSentryDebugUnitTest --tests "*.RNodeWizardViewModelTest" passes
  • ./gradlew :app:testNoSentryDebugUnitTest --tests "*.InterfaceStatsViewModelTest" passes
  • Manual: Verify RNode RSSI polling works on device without ANR

🤖 Generated with Claude Code

@sentry
Copy link
Copy Markdown
Contributor

sentry bot commented Feb 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 22, 2026

Greptile Summary

This PR fixes a background ANR issue (COLUMBA-3X) by moving synchronous AIDL binder calls off the main thread. The changes correctly wrap configManager.getRNodeRssi() calls in withContext(Dispatchers.IO) in both RNodeWizardViewModel.startRssiPolling() and InterfaceStatsViewModel.refreshStats().

Key Changes:

  • RNodeWizardViewModel.kt: Wraps getRNodeRssi() AIDL call during RSSI polling (line 454-457)
  • InterfaceStatsViewModel.kt: Wraps getRNodeRssi() call when fetching RNode stats (line 238-241)
  • Minor formatting cleanup: converts parseConfigJson() to expression body syntax

Analysis:
The fix correctly addresses the ANR root cause. The AIDL interface shows getRNodeRssi() is a synchronous blocking call that can trigger hardware reads from RNode BLE devices. Moving these calls to Dispatchers.IO prevents blocking the main thread during slow hardware operations.

Note: InterfaceStatsViewModel.kt line 209 calls reticulumProtocol.getInterfaceStats(), which already internally wraps its AIDL call in withContext(Dispatchers.IO) (ServiceReticulumProtocol.kt:2025), making the outer context switch redundant but harmless.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix correctly addresses the ANR by moving synchronous AIDL binder calls off the main thread. Tests pass, the threading model is sound, and the changes are minimal and focused.
  • No files require special attention

Important Files Changed

Filename Overview
app/src/main/java/com/lxmf/messenger/viewmodel/RNodeWizardViewModel.kt Correctly wraps getRNodeRssi() AIDL call in withContext(Dispatchers.IO) to prevent ANR during RSSI polling
app/src/main/java/com/lxmf/messenger/viewmodel/InterfaceStatsViewModel.kt Wraps getRNodeRssi() call correctly, but adds redundant withContext around already IO-dispatched getInterfaceStats() call

Last reviewed commit: e0758fe

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

getRNodeRssi() and getInterfaceStats() are synchronous AIDL binder IPC
calls that can block for seconds during BLE hardware reads. Wrapping
them in withContext(Dispatchers.IO) prevents background ANR on the
main thread while keeping coroutine lifecycle tied to viewModelScope.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@torlando-tech
Copy link
Copy Markdown
Owner Author

@greptileai

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 22, 2026

Additional Comments (1)

app/src/main/java/com/lxmf/messenger/viewmodel/InterfaceStatsViewModel.kt
reticulumProtocol.getInterfaceStats() already wraps the AIDL call in withContext(Dispatchers.IO) at ServiceReticulumProtocol.kt:2025. Consider removing the outer wrapper to reduce nesting.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/com/lxmf/messenger/viewmodel/InterfaceStatsViewModel.kt
Line: 209

Comment:
`reticulumProtocol.getInterfaceStats()` already wraps the AIDL call in `withContext(Dispatchers.IO)` at ServiceReticulumProtocol.kt:2025. Consider removing the outer wrapper to reduce nesting.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@torlando-tech torlando-tech merged commit 49b3610 into main Feb 22, 2026
14 checks passed
@torlando-tech torlando-tech deleted the fix/anr-rssi-polling branch February 22, 2026 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant