Skip to content

Commit 15a14c2

Browse files
authored
Fixing issue #650 - locked thread between location and user sync (#935)
* Fixing issue #650 - locked thread between location and user sync * SyncUserState was moving on and causing a thread lock with the complete() LocationGMS work * BlockingQueue used to make sure that the complete() callback is completely finished before moving on * Unit test broke because of null point being passed * Fixed by changing BlockArrayQueue to use a `Object` * Another unit test broke after fixing previous test * Added null check for `mGoogleApiClient` to prevent `NullPointerException`
1 parent ee6960c commit 15a14c2

File tree

3 files changed

+42
-21
lines changed

3 files changed

+42
-21
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/FocusTimeController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void doBlockingBackgroundSyncOfUnsentTime() {
6666
if (OneSignal.isForeground())
6767
return;
6868

69-
for(FocusTimeProcessorBase focusTimeProcessor : focusTimeProcessors)
69+
for (FocusTimeProcessorBase focusTimeProcessor : focusTimeProcessors)
7070
focusTimeProcessor.syncUnsentTimeFromSyncJob();
7171
}
7272

@@ -75,7 +75,7 @@ private boolean giveProcessorsValidFocusTime(@NonNull OSSessionManager.SessionRe
7575
if (timeElapsed == null)
7676
return false;
7777

78-
for(FocusTimeProcessorBase focusTimeProcessor : focusTimeProcessors)
78+
for (FocusTimeProcessorBase focusTimeProcessor : focusTimeProcessors)
7979
focusTimeProcessor.addTime(timeElapsed, lastSessionResult.session, focusType);
8080
return true;
8181
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/LocationGMS.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ public void onConnected(Bundle bundle) {
311311
synchronized (syncLock) {
312312
PermissionsActivity.answered = false;
313313

314+
if (mGoogleApiClient == null || mGoogleApiClient.realInstance() == null)
315+
return;
316+
314317
if (mLastLocation == null) {
315318
mLastLocation = FusedLocationApiWrapper.getLastLocation(mGoogleApiClient.realInstance());
316319
if (mLastLocation != null)

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalSyncServiceUtils.java

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343

4444
import com.onesignal.AndroidSupportV4Compat.ContextCompat;
4545

46+
import java.util.concurrent.ArrayBlockingQueue;
47+
import java.util.concurrent.BlockingQueue;
48+
4649
/**
4750
This schedules a job to fire later in the background preform player REST calls to make a(n);
4851
- on_focus
@@ -209,25 +212,40 @@ public final void run() {
209212
OneSignal.appId = OneSignal.getSavedAppId();
210213
OneSignalStateSynchronizer.initUserState();
211214

212-
LocationGMS.LocationHandler locationHandler = new LocationGMS.LocationHandler() {
213-
@Override
214-
public LocationGMS.CALLBACK_TYPE getType() {
215-
return LocationGMS.CALLBACK_TYPE.SYNC_SERVICE;
216-
}
217-
218-
@Override
219-
public void complete(LocationGMS.LocationPoint point) {
220-
if (point != null)
221-
OneSignalStateSynchronizer.updateLocation(point);
222-
223-
// Both these calls are synchronous.
224-
// Thread is blocked until network calls are made or their retry limits are reached
225-
OneSignalStateSynchronizer.syncUserState(true);
226-
FocusTimeController.getInstance().doBlockingBackgroundSyncOfUnsentTime();
227-
stopSync();
228-
}
229-
};
230-
LocationGMS.getLocation(OneSignal.appContext, false, locationHandler);
215+
// BlockingQueue used to make sure that the complete() callback is completely finished before moving on
216+
// SyncUserState was moving on and causing a thread lock with the complete() LocationGMS work
217+
// Issue #650
218+
// https://github.com/OneSignal/OneSignal-Android-SDK/issues/650
219+
try {
220+
final BlockingQueue<Object> queue = new ArrayBlockingQueue<>(1);
221+
LocationGMS.LocationHandler locationHandler = new LocationGMS.LocationHandler() {
222+
@Override
223+
public LocationGMS.CALLBACK_TYPE getType() {
224+
return LocationGMS.CALLBACK_TYPE.SYNC_SERVICE;
225+
}
226+
227+
@Override
228+
public void complete(LocationGMS.LocationPoint point) {
229+
Object object = point != null ? point : new Object();
230+
queue.offer(object);
231+
}
232+
};
233+
LocationGMS.getLocation(OneSignal.appContext, false, locationHandler);
234+
235+
// The take() will return the offered point once the callback for the locationHandler is completed
236+
Object point = queue.take();
237+
if (point instanceof LocationGMS.LocationPoint)
238+
OneSignalStateSynchronizer.updateLocation((LocationGMS.LocationPoint) point);
239+
240+
} catch (InterruptedException e) {
241+
e.printStackTrace();
242+
}
243+
244+
// Both these calls are synchronous
245+
// Once the queue calls take the code will continue and move on to the syncUserState
246+
OneSignalStateSynchronizer.syncUserState(true);
247+
FocusTimeController.getInstance().doBlockingBackgroundSyncOfUnsentTime();
248+
stopSync();
231249
}
232250

233251
protected abstract void stopSync();

0 commit comments

Comments
 (0)