flutter_background_geolocation icon indicating copy to clipboard operation
flutter_background_geolocation copied to clipboard

We are getting crashes in prod like ForegroundServiceStartNotAllowedException in Android 12 & SQLiteCantOpenDatabaseException in android 11 (Xiaomi phone)

Open Intellitrack2017 opened this issue 3 years ago • 12 comments

Your Environment

  • Plugin version: ^4.3.4
  • Platform: iOS or Android: Android
  • OS version: Andorid 11 and Android 12
  • Device manufacturer / model:
  • Flutter info (flutter doctor): [✓] Flutter (Channel stable, 2.5.3, on macOS 11.5.2 20G95 darwin-arm, locale en-IN) • Flutter version 2.5.3 at /Users/teja/Documents/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 18116933e7 (6 months ago), 2021-10-15 10:46:35 -0700 • Engine revision d3ea636dc5 • Dart version 2.14.4 [!] Android toolchain - develop for Android devices (Android SDK version 30.0.3) • Android SDK at /Users/user/Library/Android/sdk ✗ cmdline-tools component is missing Run path/to/sdkmanager --install "cmdline-tools;latest" See https://developer.android.com/studio/command-line for more details. ✗ Android license status unknown. Run flutter doctor --android-licenses to accept the SDK licenses. See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

Plugin config:

`void initState() { WidgetsBinding.instance.addObserver(this); _enabled = false;

//// // 1. Listen to events (See docs for all 12 available events). //

// Fired whenever a location is recorded bg.BackgroundGeolocation.onLocation((bg.Location location) { print("Locatiom $location");

});

// Fired whenever the plugin changes motion-state (stationary->moving and vice-versa) bg.BackgroundGeolocation.onMotionChange((bg.Location location) { // print(location); print("Locatiom $location");

});

bg.BackgroundGeolocation.onProviderChange((bg.ProviderChangeEvent event) { print('[Location Test App] - $event'); });

configFlutterBackGroundService();

}

configFlutterBackGroundService() async { SharedPreferences prefs = await SharedPreferences.getInstance();

////
// 2.  Configure the plugin
//
bg.BackgroundGeolocation.ready(bg.Config(
  // url: Apis.BASEURL + Apis.locations,
  // autoSync: true,
  // deferTime: 3000,
  desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
  distanceFilter: 0,
  locationUpdateInterval: 3000,
  autoSyncThreshold: 5,
  batchSync: true,
  reset: true,
  enableHeadless: true,
  stopOnTerminate: false,
  foregroundService: true,
  // isMoving: true,
  startOnBoot: true,
  heartbeatInterval: 60,
  debug: false,

  // startOnBoot: true,
  // maxBatchSize: 20,
  // headers: {
  //   "Content-Type": "application/json",
  //   "Authorization": 'Bearer ${prefs.getString(Globals.jws_token)}',
  // },
  // params: {
  //   'organizationId': prefs.getString(Globals.organizationId),
  //   'userId': prefs.getString(Globals.userIdPrefKey)
  // },
  locationsOrderDirection: "DESC",
  // maxDaysToPersist: 14
)).then((bg.State state) {
  if (!state.enabled) {
    ////
    // 3.  Start the plugin.
    //
    _enabled = state.enabled;
    checkBatteryOptimization();
  }
});

}

callStartServiceInNAtive() async {

//// // 3. Start the plugin. // bg.BackgroundGeolocation.start().then((bg.State state) { print('[start] success started $state'); _enabled = state.enabled; // To modify config after #ready has been executed, use #setConfig bg.BackgroundGeolocation.setConfig(bg.Config( isMoving: true, )).then((bg.State state) { bg.BackgroundGeolocation.sync(); }); }).catchError((error) { print('[start] starting failed ERROR: $error'); });

}

callStopServiceInNative() async {

if (_enabled) { bg.BackgroundGeolocation.stop() .then((bg.State state) => {

bg.BackgroundGeolocation.setOdometer(0.0)

}) .catchError((error) { print('[stop] stoping failed ERROR: $error'); }); } }`

Expected Behavior

We should not get any crashes in the production

Actual Behavior

We are getting 2 crashes in a production app

Crash 1:

Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.affluence.clu/com.transistorsoft.locationmanager.service.LocationRequestService at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54) at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50) at android.os.Parcel.readParcelable(Parcel.java:3379) at android.os.Parcel.createExceptionOrNull(Parcel.java:2466) at android.os.Parcel.createException(Parcel.java:2455) at android.os.Parcel.readException(Parcel.java:2438) at android.os.Parcel.readException(Parcel.java:2380) at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:6103) at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1851) at android.app.ContextImpl.startForegroundService(ContextImpl.java:1827) at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:789) at com.transistorsoft.locationmanager.service.AbstractService$a.run(AbstractService.java:10) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:233) at android.os.Looper.loop(Looper.java:344) at android.app.ActivityThread.main(ActivityThread.java:8204) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:589) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1071)

Crash 2:

Caused by android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14 SQLITE_CANTOPEN): , while compiling: PRAGMA journal_mode at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java) at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1045) at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:788) at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:405) at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:335) at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:258) at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:205) at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:505) at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:206) at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:198) at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:918) at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:898) at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:762) at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:751) at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:373) at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316) at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:4) at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:4) at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:2) at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java) at androidx.work.impl.model.SystemIdInfoDao_Impl.getWorkSpecIds(SystemIdInfoDao_Impl.java:9) at androidx.work.impl.background.systemjob.SystemJobScheduler.reconcileJobs(SystemJobScheduler.java:20) at androidx.work.impl.utils.ForceStopRunnable.cleanUp(ForceStopRunnable.java:11) at androidx.work.impl.utils.ForceStopRunnable.forceStopRunnable(ForceStopRunnable.java) at androidx.work.impl.utils.ForceStopRunnable.run(ForceStopRunnable.java:31) at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:2) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923)

Intellitrack2017 avatar May 16 '22 04:05 Intellitrack2017

See CHANGELOG and update to latest version.

christocracy avatar May 16 '22 07:05 christocracy

I've pushed a release-candidate to branch release-4.7.0. This is a major refactor in support of Android 12.

Please try it out:

dependencies
  flutter_background_geolocation:
    git:
      url: https://github.com/transistorsoft/flutter_background_geolocation
      ref: release-4.7.0

4.7.0 — Unreleased

  • [Android] Android 12: Guard Context.startForegroundService with try / catch: the plugin will now catch exception ForegroundServiceStartNotAllowedException and automatically retry with an AlarmManager oneShot event.
  • [Android] Android 12: Refactor foreground-service management for Android 12: A way has been found to restore the traditional behaviour of foreground-services, allowing them to stop when no longer required (eg: where the plugin is in the stationary state).
  • [Android] Refactor application life-cycle management. Remove deprecated permission android.permission.GET_TASKS traditionally used for detecting when the app has been terminated. The new life-cycle mgmt system can detect Android headless-mode in a much more elegant manner.
  • [Android] Better handling for WhenInUse behaviour: The plugin will not allow .changePace(true) to be executed when the app is in the background (since Android forbids location-services to initiated in the background with WhenInUse).
  • [Android] Refactor useSignificantChangesOnly behaviour. Will use a default motionTriggerDelay with minimum 60000ms, minimum distanceFilter: 250 and enforced stopTimeout: 20.
  • [iOS] iOS 15 has finally implemented Mock Location Detection. location.mock will now be present for iOS when the location is mocked, just like Android.

christocracy avatar Jun 13 '22 22:06 christocracy

This breaks my app on Android 12. The previous version of the plugin still works on Android 12.

  1. The plugin is configured to run as a foreground service.
  2. The user starts location services by clicking a button.
  3. The user shuts the screen off and leaves the phone stationary for 5 minutes.
  4. The location services notification turns off.
  5. The user starts moving again, but location services notification does not turn back on. Since this is running as a foreground service, it is still in use and should resume location updates.

bg.Config _getBgConfig() { return bg.Config( reset: true, desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH, distanceFilter: 5.0, preventSuspend: true, isMoving: true, stopOnTerminate: true, stopOnStationary: false, startOnBoot: false, stopTimeout: 5, persistMode: bg.Config.PERSIST_MODE_NONE, foregroundService: true, locationAuthorizationRequest: 'WhenInUse', ); }

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" tools:node="remove" />

ozzy1873 avatar Jun 14 '22 15:06 ozzy1873

That’s the correct behaviour. Location-services cannot be initiated in the background with WhenInUse. If you let Config.stopTimeout expire, the plugin enters the stationary state and turns off location-services.

your app must return to the foreground to re-initiate location-services (ie .changePace(true))

christocracy avatar Jun 14 '22 15:06 christocracy

Using WhenInUse doesn’t come without consequences.

christocracy avatar Jun 14 '22 15:06 christocracy

So, the only way to prevent location services from stopping in this scenario is to set stopTimeout to a really large value?

ozzy1873 avatar Jun 14 '22 16:06 ozzy1873

That’s correct.

christocracy avatar Jun 14 '22 16:06 christocracy

Can you give us an idea of the battery impact when setting stopTimeout to a really large value?

ozzy1873 avatar Jun 14 '22 16:06 ozzy1873

And you will likely want to use a sane value.

using a value of hundreds of hours would likely not be desirable to your end-user and his/her battery should they forget to launch your app and perform the action which results in .stop() / .changePace(false).

christocracy avatar Jun 14 '22 16:06 christocracy

Can you give us an idea of the battery impact

Try it and see. Let it run in that state over night.

christocracy avatar Jun 14 '22 16:06 christocracy

Will do, thanks.

ozzy1873 avatar Jun 14 '22 16:06 ozzy1873

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and I will leave this open.

stale[bot] avatar Sep 21 '22 05:09 stale[bot]