Location Permissions Causing Crash on EAS Android Build

Hi there,

I’ve noticed a few crashes from my Android application in the wild that only reproduce on an EAS build.

Callstack

2021-09-08 16:41:45.940 9194-9194/com.repro.locationcrash E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.repro.locationcrash, PID: 9194
    java.lang.RuntimeException: Unable to resume activity {com.repro.locationcrash/com.repro.locationcrash.MainActivity}: java.lang.NullPointerException
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4003)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4035)
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1940)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:209)
        at android.app.ActivityThread.main(ActivityThread.java:7046)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:486)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
     Caused by: java.lang.NullPointerException
        at java.util.Objects.requireNonNull(Objects.java:203)
        at expo.modules.location.LocationModule.handleForegroundLocationPermissions(LocationModule.java:838)
        at expo.modules.location.LocationModule.lambda$requestForegroundPermissionsAsync$2$LocationModule(LocationModule.java:195)
        at expo.modules.location.-$$Lambda$LocationModule$D--6Q7JrlKjA_yBo0ZZZH8hwBGk.onResult(Unknown Source:4)
        at org.unimodules.adapters.react.permissions.PermissionsService$createListenerWithPendingPermissionsRequest$1.onRequestPermissionsResult(PermissionsService.kt:255)
        at com.facebook.react.ReactActivityDelegate$2.invoke(ReactActivityDelegate.java:171)
        at com.facebook.react.ReactActivityDelegate.onResume(ReactActivityDelegate.java:102)
        at com.facebook.react.ReactActivity.onResume(ReactActivity.java:57)
        at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1442)
        at android.app.Activity.performResume(Activity.java:7795)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3993)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4035) 
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52) 
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1940) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:209) 
        at android.app.ActivityThread.main(ActivityThread.java:7046) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:486) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)

handleForegroundLocationPermissions is being given a null value for either the coarse location or fine location permissions inside of LocationModule.java.

Repro

  1. Create bare Expo app and install expo-location.
  2. Call Location.requestForegroundPermissionsAsync() in App.tsx.
  3. Create an EAS build of the application for Android.
  4. Install the app on a device or simulator.
  5. Enable “Always show crash dialog” to make the crashes more obvious.
  6. Open the application.
  7. When the dialog asking for location permissions appears, switch to any other app.
  8. Open the app drawer and reopen the application.
  9. Observe the crash.

Doesn’t Occur on Expo Build

Using the legacy Expo Build command does not reproduce this issue according to my testing.

Repro Project Settings

Base Expo project. Only changes to project files are as follows:

App.js

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import * as Location from 'expo-location';

export default function App() {
  const [permission, setPermission] = React.useState();

  React.useEffect(() => {
    (async () => {
      let permissionResult = await Location.requestForegroundPermissionsAsync();
      setPermission(permissionResult.status);
    })();
  }, []);

  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <Text>{permission}</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

app.json

{
  "expo": {
    "name": "location-crash",
    "slug": "location-crash",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "updates": {
      "fallbackToCacheTimeout": 0
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "ios": {
      "supportsTablet": true
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#FFFFFF"
      },
      "permissions": [
        "ACCESS_COARSE_LOCATION",
        "ACCESS_FINE_LOCATION"
      ],
      "package": "com.repro.locationcrash"
    },
    "web": {
      "favicon": "./assets/favicon.png"
    }
  }
}

package.json

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject"
  },
  "dependencies": {
    "expo": "~42.0.1",
    "expo-location": "~12.1.2",
    "expo-status-bar": "~1.0.4",
    "react": "16.13.1",
    "react-dom": "16.13.1",
    "react-native": "https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz",
    "react-native-web": "~0.13.12"
  },
  "devDependencies": {
    "@babel/core": "^7.9.0"
  },
  "private": true
}

eas.json

{
	"builds": {
		"android": {
			"apk": {
				"workflow": "managed",
				"distribution": "internal",
				"buildType": "apk"
			}
		}
	}
}

Let me know if there’s anything I can do to help reproduce on your end.

Thanks for the great write up!

I wonder if the FOREGROUND_SERVICE permission isn’t being added by default when building through EAS Build?

No problem!

I ran a build adding in the FOREGROUND_SERVICE permission, and it still reproduced.

I went one step further and added all of the differences in permissions between the Expo APK and EAS APK AndroidManifests into the app.json (minus the launch-based permissions for app icon badges) and was still able to repro.

app.json

{
  "expo": {
    "name": "location-crash",
    "slug": "location-crash",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "updates": {
      "fallbackToCacheTimeout": 0
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "ios": {
      "supportsTablet": true
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#FFFFFF"
      },
      "permissions": [
		"FOREGROUND_SERVICE",
        "ACCESS_COARSE_LOCATION",
        "ACCESS_FINE_LOCATION",
		"WAKE_LOCK",
		"MODIFY_AUDIO_SETTINGS",
		"ACCESS_WIFI_STATE",
		"RECEIVE_BOOT_COMPLETED",
		"READ_APP_BADGE"
      ],
      "package": "com.repro.locationcrash"
    },
    "web": {
      "favicon": "./assets/favicon.png"
    }
  }
}

Hi there! Just realized I hadn’t written my response as a reply. It doesn’t appear that the FOREGROUND_SERVICE permission is what’s causing the problem here.

Okay, that’s good to know!

We’re in the midst of QA for our next SDK release, so we’re going to keep our eyes out for this issue and see if we can find the root cause

Sounds good! Thanks for your help :smiley:

1 Like

Have the same crashes in bare workflow, difference only that it caused by background permission

Caused by:
java.lang.NullPointerException
	 at java.util.Objects.requireNonNull(Objects.java:220)
	 at expo.modules.location.LocationModule.handleBackgroundLocationPermissions(LocationModule.java:874)
	 at expo.modules.location.LocationModule.lambda$requestBackgroundPermissionsAsync$3$LocationModule(LocationModule.java:216)
	 at expo.modules.location.-$$Lambda$LocationModule$soRisceyv7rPN0v7taQGQLORMXw.onResult(-.java:4)
	 at org.unimodules.adapters.react.permissions.PermissionsService.createListenerWithPendingPermissionsRequest$lambda-22(PermissionsService.java:255)
	 at org.unimodules.adapters.react.permissions.PermissionsService.lambda$S4It9_1uNUL61pxORpC26eP08Lk(PermissionsService.java:0)
	 at org.unimodules.adapters.react.permissions.-$$Lambda$PermissionsService$S4It9_1uNUL61pxORpC26eP08Lk.onRequestPermissionsResult(-.java:2)
	 at com.facebook.react.ReactActivityDelegate$2.invoke(ReactActivityDelegate.java:171)
	 at com.facebook.react.ReactActivityDelegate.onResume(ReactActivityDelegate.java:102)
	 at com.facebook.react.ReactActivity.onResume(ReactActivity.java:57)
	 at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1456)
	 at android.app.Activity.performResume(Activity.java:8241)
	 at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4529)
	 at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4571)
	 at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
	 at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
	 at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
	 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2131)
	 at android.os.Handler.dispatchMessage(Handler.java:106)
	 at android.os.Looper.loop(Looper.java:250)
	 at android.app.ActivityThread.main(ActivityThread.java:7806)
	 at java.lang.reflect.Method.invoke(Method.java)
	 at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
	 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:958)

can you share a minimal reproducible example please? How to create a Minimal, Reproducible Example - Help Center - Stack Overflow