transistorsoft / cordova-background-geolocation-lt

The most sophisticated background location-tracking & geofencing module with battery-conscious motion-detection intelligence for iOS and Android.
http://www.transistorsoft.com/shop/products/cordova-background-geolocation
Other
655 stars 277 forks source link

Service stops after 5 min, even with disableStopDetection set to true #1375

Closed mlahdouri closed 1 year ago

mlahdouri commented 1 year ago

Your Environment

Expected Behavior

the tracking should not stop even in still mode after the screen is off

Actual Behavior

the tracking stop after 5 min when screen is off

Steps to Reproduce

  1. i have a function that i execute every X seconds

    
    function getMapLocation() 
    {
    BackgroundGeolocation.start().then((state) => {
      console.log("[start] success - ", state);
    });
          BackgroundGeolocation.setConfig({
            isMoving: true,
            distanceFilter: 100,
            stopTimeout : 120,
            disableStopDetection : true,
            stopOnTerminate: false,
            logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
            debug: true,
            disableMotionActivityUpdates: true,
            allowIdenticalLocations : true,
            autoSync : false
    
          }, (state) => {
                 console.log("- BackgroundGeolocation is ready, set config ok: ", state);
               });
    
        BackgroundGeolocation.getCurrentPosition({
            samples: 3,
            persist: true
        }).then((location) => {
            trackingCount++;
            deviceLat = location.coords.latitude;
            deviceLong = location.coords.longitude;
            pushLocation();
    
        }, function(error) {
                 getMapLocation();
               });

}

## Context
<!--- What were you trying to do? -->
have done all the checkups for battery optimization according to the guide at https://dontkillmyapp.com/, and have got a score of 100% on their app.

## Debug logs
<!-- include iOS / Android logs
- ios XCode logs,
- use #getLog #emailLog methods (@see docs)
- Android: $ adb logcat
-->
<details>
    <summary>Logs</summary>

```<!-- Syntax highlighting:  DO NOT REMOVE -->
PASTE_YOUR_LOGS_HERE

christocracy commented 1 year ago

See api docs Config.stopTimeout

christocracy commented 1 year ago

Also read wiki “Philosophy of Operation

mlahdouri commented 1 year ago

thanks, i have used this option as you can see in my script : stopTimeout : 120, ( is set it to 10 , but still the tracking stopes at 5 min ) also i use disableStopDetection: true, wish should keep the the service from turning OFF

also , i'm aware of the “Philosophy of Operation” my use case is : 1- The user start the tracking, 2 - Tracking should run for like 2 hours ( even when screen is off or in still position ), 3 - The user stops the tracking.

hope you can help with that :)

christocracy commented 1 year ago

See wiki Debugging and learn to fetch and observe your logs.

mlahdouri commented 1 year ago

partof-log.txt here is a log for the 5 minutes time the service was working, when screen was off

Screen is off all the time of the test starting from : 11-24 00:57:48.167 end at : 11-24 01:02:22.135 screen on at : 11-24 01:13:46.304

so at the 11-24 01:02:22.135 mark, the tracking stopes, and dosn't resume untill i turn on the screen again at 11-24 01:13:46.304

christocracy commented 1 year ago

Show me every bit of code from your app where you are interacting with BackgroundGeolocation.

mlahdouri commented 1 year ago

here is the content of the js file on the start tracking page : the function startTrack() have the BackgroundGeolocation.ready then it calls the function getMapLocation() where i do BackgroundGeolocation.setConfig ( just to be sure ) then do a BackgroundGeolocation.getCurrentPosition
getMapLocation() is executed every X seconds by the function pushLocation()

var ctRefresh = 0;
var urlParams;
var accountDataStatus = false;
var idxCustomer;
var groups = new Array();
var user = new Array();
var configurations = new Array();
var getGroupsStatus = false;
var getUserStatus = false;
var getConfigurationStatus = false;
var page_id;
var privilege;
var db;
var prvlg_user = 0;
var ctColdStorageBasket = 0;
var track_id_app;
var continueTracking = false;
var runningBackround = false;
var trackingCount = 0;
var pages = "";
var refreshRate = 6000;
var netStatus = false;

var deviceLat;
var deviceLong;
var devAccuracy;

(window.onpopstate = function () {
            var match,
                pl     = /\+/g,  // Regex for replacing addition symbol with a space
                search = /([^&=]+)=?([^&]*)/g,
                decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
                query  = window.location.search.substring(1);

            urlParams = {};
            while (match = search.exec(query))
               urlParams[decode(match[1])] = decode(match[2]);
})();

function includeHTML() {
  var z, i, elmnt, file, xhttp;
  /*loop through a collection of all HTML elements:*/
  z = document.getElementsByTagName("*");
  for (i = 0; i < z.length; i++) {
    elmnt = z[i];
    /*search for elements with a certain atrribute:*/
    file = elmnt.getAttribute("w3-include-html");
    if (file) {
      /*make an HTTP request using the attribute value as the file name:*/
      xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4) {
          if (this.status == 200) {elmnt.innerHTML = this.responseText;}
          if (this.status == 404) {elmnt.innerHTML = "Page not found.";}
          /*remove the attribute, and call this function once more:*/
          elmnt.removeAttribute("w3-include-html");
          includeHTML();
        }
      }      
      xhttp.open("GET", file, true);
      xhttp.send();
      /*exit the function:*/
      return;
    }
  }
}

    var imageOptions = {
    share: true, // default is false
    closeButton: false, // default is true
    copyToReference: true, // default is false
    headers: '',  // If this is not provided, an exception will be triggered
    piccasoOptions: { } // If this is not provided, an exception will be triggered
};

function getRefreshRate()
{//alert("getRegfresh")
    db.transaction(function(tx) 
    {
        tx.executeSql('SELECT * FROM Tracks_Configurations', [], function(tx, rs) 
        {
            for ( i = 0; i < rs.rows.length; i++ )
            {
                configurations.push(rs.rows.item(i));
            }
            refreshRate = configurations[0].refresh_rate;
        }, function(tx, error) 
        {
            //alert('SELECT Users error: ' + error.message);
        });
    });
}

function checkRunTracking(listing, totalTrack)
{
    if ((listing[listing.length-1].end_time == "" ))
    {
        continueTracking = true;
        trackingCount = totalTrack;
        track_id_app = listing[listing.length-1].track_id_app;

        runningBackround = true;
        getMapLocation();
        backModeOn();
    }

}

function backModeOn()
{
    cordova.plugins.backgroundMode.setDefaults({ text:'Status : Active '});
    // Enable background mode
    cordova.plugins.backgroundMode.enable();

    // Called when background mode has been activated
    cordova.plugins.backgroundMode.onactivate = function () 
    {
        cordova.plugins.backgroundMode.disableWebViewOptimizations(); 
        cordova.plugins.backgroundMode.disableBatteryOptimizations();
        //getMapLocation();
    }
}

function getMapLocation()
{

    BackgroundGeolocation.setConfig({
      isMoving: true,
      distanceFilter: 100,
      pausesLocationUpdatesAutomatically: false,
      stopTimeout : 10,
      disableStopDetection : true,
      stopOnTerminate: false,
      logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
      debug: true,
      disableMotionActivityUpdates: true,
      allowIdenticalLocations : true,
      autoSync : false

    }, (state) => {
           console.log("- BackgroundGeolocation is ready, set config ok: ", state);
         });

    alert("getMapLocation")
    if ( runningBackround == true )
    {

        BackgroundGeolocation.getCurrentPosition({
            samples: 3,
            persist: true
        }).then((location) => {
            //document.getElementById("locDiv").innerHTML = "Counter " + ct + "  =   \n" + location.coords.latitude + "   " + JSON.stringify(location);
            trackingCount++;
            deviceLat = location.coords.latitude;
            deviceLong = location.coords.longitude;         
            devAccuracy = location.coords.accuracy;
            //alert(pages + "  " + JSON.stringify(listing[listing.length-1]))
            if ( pages == "tracking")
            {               
                document.getElementById("gpsLat").innerHTML = deviceLat;
                document.getElementById("gpsLong").innerHTML = deviceLong;
                document.getElementById("trackingCount").innerHTML =  stringTrackingCount + "(" + trackingCount + ")";

            }
            pushLocation();
        }, function(error) {
            //BackgroundGeolocation.changePace(true);
            getMapLocation();
            bgGeo.on('heartbeat', function(params) {
              console.log('- heartbeat event received');
            });
        });
    }
}

function onMapError(error) 
{
    //alert('code: ' + error.code + '\n' +
    //'message: ' + error.message + '\n');
    getMapLocation();
}

var onMapSuccess = function (position) 
{
    //alert("onMapSuccess")
    trackingCount++;
    deviceLat = position.coords.latitude;
    deviceLong = position.coords.longitude;
    pushLocation();
}

function pushLocation()
{
    //alert("pushLocation")
    var dateTime = new Date();
    //alert(dateTime);
    dateTime = dateTime.toLocaleString('en-US', {hour12: false});
    //alert(dateTime);
    if ( continueTracking == false )
    {
        //track_id_app = uid + "" + new Date().valueOf()
    }
    //alert(continueTracking + "  " + track_id_app)
    db.transaction(function(tx) 
    {
        tx.executeSql('INSERT INTO Tracking VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)',
        [uid + "" + new Date().valueOf(), track_id_app,  dateTime, deviceLat, deviceLong, devAccuracy, "", "", "", refreshRate, user[0].user_id, uid, 0 ]);     
    }, function(error) {
            console.log('Transaction ERROR: ' + error.message);
    }, function() {
            setTimeout(getMapLocation, refreshRate);
    });
}

function startTrack()
{
                    BackgroundGeolocation.ready({
              distanceFilter: 20,
              stopTimeout : 10,
              pausesLocationUpdatesAutomatically: false,
              disableStopDetection : true,
              stopOnTerminate: false,
              logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
              debug: true
            }, (state) => {
              console.log("- BackgroundGeolocation is ready: ", state);
            });

            BackgroundGeolocation.start().then((state) => {
              console.log("[start] success - ", state);
            });

    document.getElementById("actionButton").innerHTML = "<a href=\"#\" onclick=\"stopTrack();\">" +
                                                                        "<p>STOP</p>" +
                                                                    "</a>";

    listing.length = 0;
    details.length = 0;
    //trackingCount = 0;
    var dateTime = new Date();
    dateTime = dateTime.toLocaleString('en-US', {hour12: false});
    listingId = uid + "" + new Date().valueOf();
    track_id_app = listingId;

    runningBackround = true;
        listing.length = 0;
        db.transaction(function(tx) 
        {
            tx.executeSql('SELECT * FROM Listing', [], function(tx, rs) 
            {
                for ( i = 0; i < rs.rows.length; i++ )
                {
                    listing.push(rs.rows.item(i));
                }
                setTimeout(getMapLocation,700);
                window.open("tracking.html","_blank");
            }, function(tx, error) 
            {
                alert('SELECT Listing error: ' + error.message);
            });
        });
}

function stopTrack()
{
    var text = "want to Stop?";
    if (confirm(text) == true) 
    {
        continueTracking = false;
        //cordova.plugins.backgroundMode.disable();
        runningBackround = false;
        var dateTime = new Date();
        dateTime = dateTime.toLocaleString('en-US', {hour12: false});
        //alert(dateTime + "   " + track_id_app)
        db.transaction(function(tx) {
            var query = "update Listing set end_time = ? where track_id_app = ?";
            tx.executeSql(query, [dateTime, listing[listing.length-1].track_id_app], function(tx, res) {
                console.log("insertId: " + res.insertId);
            },
            function(tx, error) {
                alert('UPDATE error: ' + error.message);
            });
        }, function(error) {
                //console.log('Transaction ERROR: ' + error.message);
                alert('Download Product Transaction ERROR: ' + error.message);
        }, function() {
                listing.length = 0;
                document.getElementById("actionButton").innerHTML = startTrackButton;
                window.open("index.html","_blank");
                //showTrack();
        });
    }

    BackgroundGeolocation.logger.emailLog('myemail@mailprovider.com').then((success) => {
      console.log('[emailLog] SUCCESS');
    }).catch((error) => {
      console.log('[emailLog] ERROR: ', error);
    });
}
christocracy commented 1 year ago

where i do BackgroundGeolocation.setConfig ( just to be sure )

Sure of what??

This is incorrect usage, as warned in the README.

Screen Shot 2022-11-24 at 9 22 50 AM
BackgroundGeolocation.ready({
  distanceFilter: 20,
  stopTimeout : 10,
  pausesLocationUpdatesAutomatically: false,
  disableStopDetection : true,
  stopOnTerminate: false,
  logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
  debug: true
}, (state) => {
  console.log("- BackgroundGeolocation is ready: ", state);
});

// NO!  You CANNOT call .start() before callback to .ready has fired!!!!!!!!!!!!
BackgroundGeolocation.start().then((state) => {
  console.log("[start] success - ", state);
});
BackgroundGeolocation.ready(config, function(state) {
  // Background Geolocation is now ready to use.

  if (!state.enabled) {
    // YES!  OK to call .start() here.
    BackgroundGeolocation.start();
  } 
});

// NO!!!!!!!!!!!!!  .ready() callback has not fired!
BackgroundGeolocation.start();
christocracy commented 1 year ago

This is some ancient-looking code. Are you a developer who has taken over an old project?

christocracy commented 1 year ago

You know you have a potential memory leak, adding an onHeartbeat listener each time your error callback to getCurrentPosition fires?

bgGeo.on('heartbeat', function(params) {
  console.log('- heartbeat event received');
});

Seriously?? You're going to run that function every 700ms?? Your app is probably running out of memory and the device overheating.

setTimeout(getMapLocation,700);
christocracy commented 1 year ago

setTimeout(getMapLocation,700);

Oh, sorry...that's not setInterval. Still weird.

mlahdouri commented 1 year ago

yes i'm trying to help to figure this out with my devlopper

christocracy commented 1 year ago

Your app is stuck in some sort of loop calling .ready() and/or .start() over and over again.

You likely have some code in the app pause / resume event interacting with the plugin.

It's important to be aware that the PLUGIN ITSELF causes pause/resume events to occur on Android (see Config.disableLocationAuthorizationAlert.

Your logs are full of this, over and over and over


11-24 00:58:17.162 DEBUG [LifecycleManager onPause] ☯️  onPause
11-24 00:58:17.162 DEBUG [LifecycleManager onStop] ☯️  onStop
.
.
.
  🔵  Acquired motionchange position, isMoving: true
.
.
.
11-24 00:58:23.395 DEBUG [LifecycleManager onStart] ☯️  onStart
11-24 00:58:23.398 DEBUG [LifecycleManager onResume] ☯️  onResume
...
christocracy commented 1 year ago

whatever your problem is, it's your own code responsible.

christocracy commented 1 year ago

It's like you're calling .start() every 6-8 seconds.

11-24 00:57:48.991 INFO [TSLocationManager onSingleLocationResult] 
  🔵  Acquired motionchange position, isMoving: true

11-24 00:57:55.984 INFO [TSLocationManager onSingleLocationResult] 
  🔵  Acquired motionchange position, isMoving: true

11-24 00:58:02.998 INFO [TSLocationManager onSingleLocationResult] 
  🔵  Acquired motionchange position, isMoving: true

11-24 00:58:10.044 INFO [TSLocationManager onSingleLocationResult] 
  🔵  Acquired motionchange position, isMoving: true

11-24 00:58:16.995 INFO [TSLocationManager onSingleLocationResult] 
  🔵  Acquired motionchange position, isMoving: true

11-24 00:58:23.989 INFO [TSLocationManager onSingleLocationResult] 
  🔵  Acquired motionchange position, isMoving: true
mlahdouri commented 1 year ago

it's BackgroundGeolocation.getCurrentPosition that is executed every 6 seconds, we need this to get the current position and save it on the DB

christocracy commented 1 year ago

What's the point calling .start() and .setConfig every 6 seconds?!?

Get rid of that.

If you want the location every 6 seconds just call .getCurrentPosition()

mlahdouri commented 1 year ago

here i have moved the bgGeo.ready to the onDeviceReady :

function onDeviceReady() {
    db = window.sqlitePlugin.openDatabase({
        name: 'my.db',
        location: 'default',
    });

    uid = device.uuid;
    pages = "tracking";

    // 1.  Listen to events
  var bgGeo = window.BackgroundGeolocation;

  bgGeo.onLocation(function(location) {
    console.log('[location] -', location);
  });

  bgGeo.onMotionChange(function(event) {
    console.log('[motionchange] -', event.isMoving, event.location);
  });

  bgGeo.onProviderChange(function(event) {
    console.log('[providerchange] -', event.status, event.enabled, event.gps, event.network);
  });

  // 2. Execute #ready method:
  bgGeo.ready({
    debug: true,
    logLevel: bgGeo.LOG_LEVEL_VERBOSE,
    desiredAccuracy: bgGeo.DESIRED_ACCURACY_HIGH,
    stopTimeout: 14,
        pausesLocationUpdatesAutomatically: false,
        disableStopDetection: true,
        stopOnTerminate: false,
    startOnBoot: true,
    isMoving: true,
    distanceFilter: 100,
    disableMotionActivityUpdates: true,
    allowIdenticalLocations : true,
    autoSync : false
  }, function(state) {    // <-- Current state provided to #configure callback
    // 3.  Start tracking
    console.log('BackgroundGeolocation is configured and ready to use');
    if (!state.enabled) {
      bgGeo.start().then(function() {
        console.log('- BackgroundGeolocation tracking started');
      });
    }
  });
}

then only call .getCurrentPosition() inside function getMapLocation()

function getMapLocation()
{
    if ( runningBackround == true )
    {
        BackgroundGeolocation.getCurrentPosition({
            samples: 3,
            persist: true
        }).then((location) => {
            trackingCount++;
            deviceLat = location.coords.latitude;
            deviceLong = location.coords.longitude;         
            devAccuracy = location.coords.accuracy;         
            pushLocation();
        }, function(error) {
            getMapLocation();
        });
    }
}
christocracy commented 1 year ago

do you know that the plugin has its own http service and SQLite database?

see api docs Config.url

mlahdouri commented 1 year ago

yes, but we use our own function for that, as we have other type of inserts

mlahdouri commented 1 year ago

also we give the user the choice to sync or not

christocracy commented 1 year ago

Then do you know that each time you call getCurrentPosition with persist: true, the plugin inserts a new record into its database, that you’re never going to use?

I suggest you call .getCount() and see how many records you’ve got inserted in the plugin db.

also see api docs Config.maxRecordsToPersist, Config.maxDaysToPersist

christocracy commented 1 year ago

autoSync : false

This option is ignored if you don’t provide the plugin an url

christocracy commented 1 year ago

stopOnTerminate: false,

Do you know that your app is not uploading or storing anything in your SQLite db when the app is running terminated, even though the plugin continues to track?

mlahdouri commented 1 year ago

i see what you mean, we can use the http service , but the problem now is that the tracking still stops after 5 min, after the edit i sent you

christocracy commented 1 year ago

I suggest go test my SampleApp on your device.

It’s available on the Play Store and linked in the readme.

christocracy commented 1 year ago

I also suggest you build yourself a simple HelloWorld app and test that.