-
Notifications
You must be signed in to change notification settings - Fork 29
Android crash: NullPointerException in RoadSnappedLocationProvider.LocationListener.onRawLocationUpdate #560
Description
Bug description
Calling stopUpdatingLocation (which calls removeLocationListener) can cause a fatal NullPointerException on Android. The crash occurs inside the Navigation SDK's internal code when onRawLocationUpdate is invoked on a listener reference that has been nulled during concurrent removal.
Stack trace
Fatal Exception: java.lang.NullPointerException: Attempt to invoke interface method
'void com.google.android.libraries.navigation.RoadSnappedLocationProvider$LocationListener
.onRawLocationUpdate(android.location.Location)' on a null object reference
at com.google.android.libraries.navigation.internal.aas.gz.b(PG:1)
at com.google.android.libraries.navigation.internal.xz.e.a(PG:9)
at com.google.android.libraries.navigation.internal.io.l.b(PG:8)
at com.google.android.libraries.navigation.internal.io.i.h(PG:1)
at com.google.android.libraries.navigation.internal.io.n.run(n.java:1)
at android.os.Handler.handleCallback(Handler.java:995)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loopOnce(Looper.java:273)
at android.os.Looper.loop(Looper.java:363)
at android.app.ActivityThread.main(ActivityThread.java:9939)
Root cause
There is a race condition between the SDK's internal location-delivery thread and NavModule.removeLocationListener():
- The SDK's internal thread prepares to invoke
listener.onRawLocationUpdate(location) - Concurrently,
stopUpdatingLocation→removeLocationListener()callsmRoadSnappedLocationProvider.removeLocationListener(mLocationListener), which nulls the SDK's internal reference to the listener - The SDK's internal thread then tries to invoke the method on the now-null reference → NPE
The entire crash stack is within com.google.android.libraries.navigation.internal.* (obfuscated), confirming this is a thread-safety issue in the SDK's listener dispatch.
Suggested fix
The onLocationChanged and onRawLocationUpdate callbacks in NavModule already guard on the mIsListeningRoadSnappedLocation flag and are no-ops when it is false. Therefore, it is safe to not call removeLocationListener() during normal start/stop cycles — just toggle the flag. The listener should only be fully removed during cleanup().
// Before (crashes):
@Override
public void stopUpdatingLocation(final Promise promise) {
mIsListeningRoadSnappedLocation = false;
removeLocationListener(); // ← triggers SDK race condition
promise.resolve(null);
}
// After (safe):
@Override
public void stopUpdatingLocation(final Promise promise) {
mIsListeningRoadSnappedLocation = false;
// Don't remove the listener — callbacks are already no-ops when flag is false.
promise.resolve(null);
}Similarly, registerLocationListener() should skip the remove-and-recreate cycle if a listener is already registered:
private void registerLocationListener() {
if (mLocationListener != null) {
return; // Already registered; just flip the flag in startUpdatingLocation
}
// ... create and register new listener ...
}Environment
@googlemaps/react-native-navigation-sdk: 0.14.2com.google.android.libraries.navigation:navigation: 7.4.0- Platform: Android
- Crash observed on production devices via Crashlytics