expo: NPE Crash in GeofencingTaskConsumer.didExecuteJob()
🐛 Bug Report
Environment
Expo CLI 3.0.6 environment info:
System:
OS: macOS 10.14.5
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 12.6.0 - ~/.nvm/versions/node/v12.6.0/bin/node
Yarn: 1.17.3 - ~/.nvm/versions/node/v12.6.0/bin/yarn
npm: 6.9.0 - ~/.nvm/versions/node/v12.6.0/bin/npm
IDEs:
Android Studio: 3.4 AI-183.6156.11.34.5692245
Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild
npmPackages:
expo: ^33.0.4 => 33.0.5
react: 16.8.3 => 16.8.3
react-native: https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz => 0.59.8
react-navigation: ^3.11.0 => 3.11.0
npmGlobalPackages:
expo-cli: 3.0.6
Seems to be a problem on Android only. I’ve been testing on a Pixel 2 running Android 9.
Steps to Reproduce
- Clone the reproducable case below
- Build and install the app on your phone as a standalone app
- Open and close the app in quick succession to reproduce.
If you’re tailing the logs you should see:
--------- beginning of crash
2019-08-05 16:14:17.516 10944-10944/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.faketown.usa, PID: 10944
java.lang.RuntimeException: java.lang.NullPointerException: Attempt to invoke interface method 'void org.unimodules.b.j.d.execute(android.os.Bundle, java.lang.Error)' on a null object reference
at android.app.job.JobServiceEngine$JobHandler.handleMessage(JobServiceEngine.java:112)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void org.unimodules.b.j.d.execute(android.os.Bundle, java.lang.Error)' on a null object reference
at expo.modules.location.taskConsumers.GeofencingTaskConsumer.didExecuteJob(GeofencingTaskConsumer.java:128)
at expo.modules.taskManager.TaskService.handleJob(TaskService.java:331)
at expo.modules.taskManager.TaskJobService.onStartJob(TaskJobService.java:13)
at android.app.job.JobService$1.onStartJob(JobService.java:62)
at android.app.job.JobServiceEngine$JobHandler.handleMessage(JobServiceEngine.java:108)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Additional Context
In order to troubleshoot I ejected and added some additional logging and null checks to GeofencingTaskConsumer:
@Override
public boolean didExecuteJob(JobService jobService, JobParameters params) {
if (mTask == null) {
Log.i(TAG, "--------->mTask is null at the beginning of didExecuteJob().");
return false;
}
List<PersistableBundle> data = getTaskManagerUtils().extractDataFromJobParams(params);
for (PersistableBundle item : data) {
Bundle bundle = new Bundle();
Bundle region = new Bundle();
region.putAll(item.getPersistableBundle("region"));
bundle.putInt("eventType", item.getInt("eventType"));
bundle.putBundle("region", region);
if (mTask == null) {
Log.e(TAG, "--------->mTask is null now, but wasn't when this method was called.");
return false;
}
mTask.execute(bundle, null);
}
return true;
}
I noticed that the member variable mTask can be set to null by didUnregister while didExecuteJob is still doing work so perhaps this is a thread safety issue?
There may be a better way, but adding the null check and early return in the middle of the for loop did stop the crashing for me.
Expected Behavior
The app should not crash when you restart a Geofence task by adding/removing regions, etc.
Actual Behavior
The app can crash when mTask is set to null while didExecuteJob is still doing work.
Reproducible Demo
I am unable to share our actual app, but here’s a small app that I’ve used to reproduce this problem. Clone it, build and run it on your phone as a standalone app, and open and close it in quick succession. Note, that our actual app may run for several hours or even days without encountering this crash, but eventually it happens. Opening and closing quickly (or anything that would call startAsync on the task multiple times in a short amount of time ) seems to be the quickest way to reproduce.
Thanks!
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 3
- Comments: 15 (10 by maintainers)
I am also seeing similar issues on Android (expo and standalone) when using Geofencing. Is there a way to fix this/get around this without ejecting at JavaScript level?
Hey @briefjudofox, Yeah, thanks for posting an issue and giving us enough details 😉 I’ve assigned @Szymon20000 to take care of this as he may have more bandwidth than I to fix this before SDK36 release. We’ll keep you posted here 🙂