Skip to content

fix: prevent location permission crashes from FusedLocation API calls#2653

Open
Protactinium234 wants to merge 2 commits into
OneSignal:mainfrom
Protactinium234:main
Open

fix: prevent location permission crashes from FusedLocation API calls#2653
Protactinium234 wants to merge 2 commits into
OneSignal:mainfrom
Protactinium234:main

Conversation

@Protactinium234

Copy link
Copy Markdown

Description

One Line Summary

Add try/catch to cancelLocationUpdates

Details

Motivation

App crashes on reopen due to java.lang.SecurityException: no location permission

type: crash
osVersion: google/bluejay/bluejay:16/BP4A.251205.006/2026050901:user/release-keys
package: com.fig:14968, targetSdk 36
process: com.fig
processUptime: 20962 + 909 ms
installer: com.android.vending

java.lang.SecurityException: no location permission
	at app.grapheneos.gmscompat.location.Client.<init>(Client.kt:23)
	at app.grapheneos.gmscompat.location.Client.<init>(Client.kt:9)
	at app.grapheneos.gmscompat.location.GLocationService.unregisterLocationReceiver(GLocationService.kt:81)
	at com.google.android.gms.location.internal.IGoogleLocationManagerService$Stub.onTransact(IGoogleLocationManagerService.java:232)
	at android.os.Binder.transact(Binder.java:1351)
...
	at com.google.android.gms.internal.location.zzau.removeLocationUpdates(com.google.android.gms:play-services-location@@21.0.1:3)
	at com.onesignal.location.internal.controller.impl.FusedLocationApiWrapperImpl.cancelLocationUpdates(FusedLocationApiWrapperImpl.kt:17)
	at com.onesignal.location.internal.controller.impl.GmsLocationController$LocationUpdateListener.refreshRequest(GmsLocationController.kt:203)
	at com.onesignal.location.internal.controller.impl.GmsLocationController$LocationUpdateListener.onFocus(GmsLocationController.kt:180)
	at com.onesignal.core.internal.application.impl.ApplicationService$handleFocus$1.invoke(ApplicationService.kt:395)
	at com.onesignal.core.internal.application.impl.ApplicationService$handleFocus$1.invoke(ApplicationService.kt:395)
	at com.onesignal.common.events.EventProducer.fire(EventProducer.kt:50)
	at com.onesignal.core.internal.application.impl.ApplicationService.handleFocus(ApplicationService.kt:395)
	at com.onesignal.core.internal.application.impl.ApplicationService.onActivityStarted(ApplicationService.kt:163)
	at android.app.Application.dispatchActivityStarted(Application.java:422)
...
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:566)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:837)

Manual testing

Now gracefully handles exception

[DefaultDispatcher-worker-10] FusedLocationApi.requestLocationUpdates failed!
java.lang.SecurityException: no location permission
	at app.grapheneos.gmscompat.location.Client.<init>(Client.kt:23)
	at app.grapheneos.gmscompat.location.Client.<init>(Client.kt:9)
	at app.grapheneos.gmscompat.location.GLocationService.registerLocationReceiver(GLocationService.kt:49)
	at com.google.android.gms.location.internal.IGoogleLocationManagerService$Stub.onTransact(IGoogleLocationManagerService.java:221)
...
	at com.onesignal.location.internal.controller.impl.GmsLocationController$start$2.invokeSuspend(GmsLocationController.kt:62)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:101)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:113)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:589)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:823)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:720)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:707)

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
    • If it is hard to explain how any codes changes are related to each other then it most likely needs to be more than one PR
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@nan-li nan-li requested a review from a team June 17, 2026 18:39
@nan-li

nan-li commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Hi @Protactinium234 thanks for submitting this PR, we will get it merged and shipped

@fadi-george

Copy link
Copy Markdown
Contributor

@claude review

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — mirrors the existing try/catch pattern in requestLocationUpdates within the same file to handle the same SecurityException class.

Extended reasoning...

Overview

This PR adds a defensive try/catch wrapper to FusedLocationApiWrapperImpl.cancelLocationUpdates, mirroring the identical pattern already present on requestLocationUpdates in the same file. The change addresses a real crash (SecurityException: no location permission) observed on grapheneos/gmscompat where the permission check happens server-side in the GMS binder, so the isConnected guard cannot catch it.

Security risks

None. The change only catches and logs a Throwable; it does not weaken any permission/authentication checks. Failure mode is now a logged warning instead of an app crash, which is the intended behavior.

Level of scrutiny

Low. The diff is 8 lines in a single method, follows an established defensive pattern present one method below it in the same file, and has a clear, documented crash to motivate it. The PR author manually verified the fix and a maintainer (nan-li) has already indicated intent to merge.

Other factors

The bug hunter found one pre-existing issue: getLastLocation in the same wrapper lacks equivalent protection and could throw the same SecurityException. That is a reasonable follow-up but is explicitly out of scope for this PR (the diff does not touch those lines), so it does not block approval. The inline comment is posted for the author's awareness.

@fadi-george fadi-george changed the title Add try/catch to cancelLocationUpdates fix: add try/catch to cancelLocationUpdates Jun 17, 2026
Mirror the guard on requestLocationUpdates/cancelLocationUpdates so a SecurityException from the GMS binder (e.g. a revoked or server-side denied location permission) is logged instead of crashing.

Co-authored-by: Cursor <cursoragent@cursor.com>
@nan-li nan-li changed the title fix: add try/catch to cancelLocationUpdates fix: prevent location permission crashes from Google Play Services calls Jun 18, 2026
@nan-li nan-li changed the title fix: prevent location permission crashes from Google Play Services calls fix: prevent location permission crashes from FusedLocation API calls Jun 18, 2026
@nan-li

nan-li commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

@claude review

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the added try/catch on getLastLocation matches the prior pattern in requestLocationUpdates and closes the gap I flagged.

Extended reasoning...

Overview

This PR adds defensive try/catch blocks around two methods in FusedLocationApiWrapperImpl.kt: cancelLocationUpdates (the original fix for the reported SecurityException crash on gmscompat) and getLastLocation (added after my prior review pointed out it had the same gap). Both now follow the same pattern already in use by requestLocationUpdates: wrap the isConnected guard + LocationServices.FusedLocationApi call in try/catch and log via Logging.warn on Throwable.

Security risks

None. This is a purely defensive change that broadens existing exception handling. It does not introduce new permissions, IPC surface, data flow, or auth logic — it just prevents an already-crashing path from terminating the host app.

Level of scrutiny

Low. The change is mechanical, ~10 lines, follows an established intra-file pattern (requestLocationUpdates already had the identical guard), and is supported by a real crash report with a clear stack trace in the PR description. The maintainer (nan-li) already engaged with my prior comment, clarified that the follow-up should land here rather than in a separate PR, and re-requested review after the author addressed it.

Other factors

The current diff is exactly the change I recommended in my prior review (matching the catch-Throwable + warn-log convention used elsewhere in the file and in HmsLocationController.getLastLocation). Returning null from the catch path preserves existing call-site semantics — GmsLocationController already treats a null result from getLastLocation as a no-op. No new behavior, no API surface change, no test coverage needed beyond what the wrapper already implies.

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.

3 participants