Skip to content

Only unregister actionReceiver when it was registered#6628

Merged
TimoPtr merged 3 commits intomainfrom
fix/unregister_not_register_receiver
Mar 30, 2026
Merged

Only unregister actionReceiver when it was registered#6628
TimoPtr merged 3 commits intomainfrom
fix/unregister_not_register_receiver

Conversation

@TimoPtr
Copy link
Copy Markdown
Member

@TimoPtr TimoPtr commented Mar 26, 2026

Summary

Fix a crash from Sentry where we unregistered the actionReceiver before we actually register it in onReady. I must be hard to reproduce like switching the service very quick from HA to Google for instance. This PR guard this behavior by only setting the attribute when it is registered.

Checklist

  • New or updated tests have been added to cover the changes following the testing guidelines.
  • The code follows the project's code style and best_practices.
  • The changes have been thoroughly tested, and edge cases have been considered.
  • Changes are backward compatible whenever feasible. Any breaking changes are documented in the changelog for users and/or in the code for developers depending on the relevance.

Raw error from Sentry

IllegalArgumentException: Receiver not registered: io.homeassistant.companion.android.assist.service.AssistVoiceInteractionService$actionReceiver$1@ae8f1fb

Project: android
Date: 3/28/2026, 2:29:33 PM

Issue Summary

Unregistered Receiver Exception in Assist Service Shutdown
What's wrong: IllegalArgumentException during receiver unregistration in AssistVoiceInteractionService.
In the trace: Breadcrumbs show only device orientation changes; no direct link to the crash.
Possible cause: The actionReceiver was likely unregistered prematurely or twice during service shutdown.

Tags

  • device: SM-S921B
  • device.class: high
  • device.family: SM-S921B
  • dist: 21150
  • environment: production
  • handled: no
  • installerStore: com.android.vending
  • isSideLoaded: false
  • level: fatal
  • mechanism: UncaughtExceptionHandler
  • os: Android 16
  • os.build: BP2A.250605.031.A3.S921BXXSDCZB2
  • os.name: Android
  • os.rooted: no
  • release: io.homeassistant.companion.android@2026.3.6

Exception

Exception 1

Type: IllegalArgumentException
Value: Receiver not registered: io.homeassistant.companion.android.assist.service.AssistVoiceInteractionService$actionReceiver$1@ae8f1fb

Stacktrace

 forgetReceiverDispatcher in LoadedApk.java [Line 1815] (Not in app)
 unregisterReceiver in ContextImpl.java [Line 2023] (Not in app)
 unregisterReceiver in ContextWrapper.java [Line 860] (Not in app)
 onShutdown in AssistVoiceInteractionService.kt [Line 106] (In app)
 onShutdownInternal in VoiceInteractionService.java [Line 389] (Not in app)
 -$$Nest$monShutdownInternal in unknown file [Line 0] (Not in app)
 $r8$lambda$wfImATncamP2VQNcSOIvVvfph5M in unknown file [Line 0] (Not in app)
 accept in D8$$SyntheticClass [Line 0] (Not in app)
 doInvoke in PooledLambdaImpl.java [Line 267] (Not in app)
 invoke in PooledLambdaImpl.java [Line 204] (Not in app)
 run in OmniFunction.java [Line 87] (Not in app)
 handleCallback in Handler.java [Line 995] (Not in app)
 dispatchMessage in Handler.java [Line 103] (Not in app)
 loopOnce in Looper.java [Line 273] (Not in app)
 loop in Looper.java [Line 363] (Not in app)
 main in ActivityThread.java [Line 10060] (Not in app)

Copilot AI review requested due to automatic review settings March 26, 2026 09:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a crash in AssistVoiceInteractionService where onShutdown() could attempt to unregister a broadcast receiver before it had been registered, based on Sentry reports of fast assistant switching/race conditions.

Changes:

  • Make actionReceiver nullable and only unregister it when non-null
  • Instantiate/register the receiver during onReady() rather than at property initialization
  • Add a regression test ensuring onShutdown() before onReady() does not crash

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
app/src/main/kotlin/io/homeassistant/companion/android/assist/service/AssistVoiceInteractionService.kt Guard receiver unregistration by tracking registration state via a nullable receiver reference
app/src/test/kotlin/io/homeassistant/companion/android/assist/service/AssistVoiceInteractionServiceTest.kt Add regression coverage for calling onShutdown() before onReady()

Comment on lines +72 to 86
/** Non-null only while the receiver is registered (between [onReady] and [onShutdown]). */
private var actionReceiver: BroadcastReceiver? = null

override fun onReady() {
super.onReady()
isServiceReady = true
Timber.d("VoiceInteractionService is ready")
actionReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
handleAction(intent.action)
}
}
ContextCompat.registerReceiver(
this,
actionReceiver,
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

The new KDoc says actionReceiver is non-null only while the receiver is registered, but it’s assigned before ContextCompat.registerReceiver(...) is called. If registration were to throw, actionReceiver would remain non-null even though it was never registered, and onShutdown could still attempt to unregister it. Consider creating the receiver as a local val, registering it, and only then assigning it to actionReceiver (or adjust the KDoc to match the actual lifecycle).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think it is acceptable tbh if it crashes on registerReceiver the app crashes already.

@TimoPtr TimoPtr requested a review from jpelgrom March 26, 2026 09:51
Comment on lines +361 to +362
// Reproduces Sentry:ANDROID-27RA: onShutdown called before onReady should not throw
// IllegalArgumentException for unregistering a receiver that was never registered
Copy link
Copy Markdown
Member

@jpelgrom jpelgrom Mar 27, 2026

Choose a reason for hiding this comment

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

Please remove the reference to the private Sentry issue or include a link to the PR/GitHub with the trace. This currently doesn't help the majority of contributors without access to Sentry. (I think the description after the Sentry reference is descriptive enough and it can be removed.)

@TimoPtr TimoPtr enabled auto-merge (squash) March 30, 2026 08:11
@TimoPtr TimoPtr merged commit 7383f88 into main Mar 30, 2026
23 checks passed
@TimoPtr TimoPtr deleted the fix/unregister_not_register_receiver branch March 30, 2026 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants