Foreground Service restarts on didExitRegion

Clash Royale CLAN TAG#URR8PPP
Foreground Service restarts on didExitRegion
I'm building an app to detect iBeacons on Android. The basic functionality is to store the advertised data by the beacon onto the device and upload it to a server. For this purpose, I'm using Android Beacon Library.
To run it in the background on Android O I'm using foreground services. The problem is when the App is in the background for more than 30 mins, after detecting a beacon, when the user exits the beacon region and didExitRegion is called, somehow, the service is automatically killed and it restarts thus no data is uploaded to the server. Also after restarting, on a second didExitRegion call, it stops completely and randomly sometime in the future, it restarts but to do the same loop all over again.
didExitRegion
didExitRegion
Sequence of events as they happen when app comes in regions after being inactive for around 30min
First Restart after didExit (Image)
Here you can see switching from region 11 to 9. Midway app closed and retriggered instantaneously, however no push was sent
Exit after second didExit (Image)
Next up: when exiting from this region now, app again stops in the background. But this time does not get re-triggered immediately. This is the exact sequence taking place always.
Code Snippets
BeaconScanner.java
@Override
public void didExitRegion(Region region)
Log.d(TAG, "Exited A Region");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
notificationHelper.notify(2, notificationHelper.getNotification("BeaconScanner", "Exit Major #"+previousMajor, false));
else
utils.dispatchNotification("Exit Major #"+previousMajor, 1);
Log.e(TAG, "DidSend "+didSend+" has Data "+userData.hasPendingData());
if(didSend && userData.hasPendingData())
JSONObject data = userData.getJsonFromUser();
Log.d(TAG, "Timestamp = "+System.currentTimeMillis());
userData.addTimestamp(""+System.currentTimeMillis());
userData.requestDataSync(data);
userData.clearBeaconData();
Log.d(TAG, data.toString());
didSend = !didSend;
previousMajor = -1000;
lastBeacon = resetBeacon;
User.java
JSONObject getJsonFromUser()
Log.d(TAG, "Timestamp as in getJsonFromUser "+timestamp);
JSONObject json = new JSONObject();
try
json.put("email", email);
json.put("name", name);
JSONArray beaconArray = new JSONArray();
for (Beacon beacon : beaconData)
beaconArray.put(new JSONObject()
.put("major", beacon.getId2().toInt())
.put("minor", beacon.getId3().toInt())
.put("uuid", beacon.getId1().toString())
);
json.put("data", beaconArray);
Log.d(TAG, timestamp);
json.put("timestamp", ""+System.currentTimeMillis());
return json;
catch (Exception e)
Log.e(TAG, e.getMessage());
Crashlytics.log(e.getLocalizedMessage());
return json;
void requestDataSync(final JSONObject json){
User.syncing = true;
Crashlytics.log(1, "User.java", "Requesting Auth Token");
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.getIdToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>()
@Override
public void onComplete(@NonNull Task<GetTokenResult> task)
if(task.isSuccessful())
final Task<GetTokenResult> t = task;
Thread thread = new Thread(new Runnable()
@Override
public void run()
try
trustAllHosts();
URL url = new URL("https://indpulse.com/generatetoken");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setHostnameVerifier(DO_NOT_VERIFY);
connection.setRequestProperty("Authorization", ""+t.getResult().getToken());
connection.setRequestMethod("GET");
Log.d(TAG, t.getResult().getToken());
connection.setDoOutput(true);
connection.connect();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String packet;
while((packet = br.readLine()) != null)
response.append(packet);
JSONObject responseObject = new JSONObject(response.toString());
String idToken = responseObject.getString("token");
Crashlytics.log(1, "User.java", "Auth Token Acquired");
sendData(json, idToken);
catch (MalformedURLException e)
Log.e(TAG, "Malformed URL "+e.getLocalizedMessage());
Crashlytics.log(e.getLocalizedMessage());
catch (IOException e)
Log.e(TAG, "IOExeption "+e.getLocalizedMessage());
Crashlytics.log(e.getLocalizedMessage());
catch (JSONException e)
Log.d(TAG,"Json error");
Crashlytics.log(e.getLocalizedMessage());
);
thread.start();
);
void sendData(JSONObject json, final String idToken)
final String sJson = json.toString();
System.out.println(sJson);
Thread thread = new Thread(new Runnable()
@Override
public void run()
try
URL url = new URL("https://indpulse.com/android");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer "+idToken);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
DataOutputStream os = new DataOutputStream(conn.getOutputStream());
os.writeBytes(sJson);
os.flush();
os.close();
Log.i(TAG, String.valueOf(conn.getResponseCode()));
Log.i(TAG , conn.getResponseMessage());
conn.disconnect();
catch (Exception e)
Log.e("BeaconScanner", e.getLocalizedMessage());
Crashlytics.log(e.getLocalizedMessage());
User.syncing = false;
);
thread.start();
EDIT 1
One thing to note is that the beacons have an overlapping region, i.e a beacon scanner will detect 2 beacons in the region. So the nearest beacon is decided by the greatest value of the timeAverageRssi, the bug specifically crops up, after 30 minutes of inactivity there are region switches i.e beacon 1 was the nearest and then beacon 2 becomes the nearest beacon
timeAverageRssi
How do you create your foreground service? Do you make the Android Beacon LIbrary's built-in scanning service a foreground service as described here? Or do you have an independent custom foreground service in your app? Do you make any configuration calls to
beaconManager.setEnableScheduledScanJobs(...) ?– davidgyoung
Aug 11 at 15:46
beaconManager.setEnableScheduledScanJobs(...)
So, I have both. Does it make any difference? Yes, I set beaconManager.setEnableScheduledScanJobs(false). I'll use the 2.15.1 beta 1 version library and see if it fixes the issue
– Arvind Rachuri
Aug 12 at 5:27
No, I don't get any log capture when the app crashes. The service just stops.
– Arvind Rachuri
Aug 12 at 10:06
I would focus on adding more logging to your app and also watch for any operating system log messages around the time the app stops running. We will need more info to figure out what is stopping the app from running.
– davidgyoung
Aug 12 at 12:54
1 Answer
1
I suspect a bug with using foreground services with the Android Beacon Library version 2.15 on Android 8+. While I have not reproduced this myself, the theory is that Android 8+ blocks the usage of an Intent Service used to deliver monitoring callbacks from the beacon scanning service.
I built a proposed fix in library version 2.15.1 beta 1 based on a similar report issue here. Please try this fix and see if it solves your problem.
Hi, it is still behaving the same. A couple of more details on the issue : * The issue seems to be cropping up only in OnePlus 5T till now of all the phones used to test * The library works fine with Xiaomi Mi Max 2 - with a PixelExperience custom ROM * Also, the app gets restarted because I have a job scheduler which restarts the service when it exits in anyway. Hope these details will provide a bit more insight into the issue
– Arvind Rachuri
Aug 12 at 9:56
Update - This fix worked for me if you are facing the same problem you might want to try this.
– Arvind Rachuri
Aug 24 at 13:53
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
By any chance can you get a log capture when the app crashes?
– davidgyoung
Aug 11 at 12:23