-
Notifications
You must be signed in to change notification settings - Fork 836
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix intermittent scans #489
Conversation
All of the other time trackers in `CycledLeScanner` use the elapsed time. I think it was simply an oversight when the change was made to guard against the Android N (Android 7, API 24+) behavior of limiting scan starts to only five every thirty seconds. However, using the system time causes an issue where the scan will never stop. This happens when the time is changed to the past or was set to the future then return to normal or past time. Once `mLastScanStopTime` is set if the system time ever goes backwards the calculation `now - mLastScanStopTime` will always be negative. Thus it will always be less than the `ANDROID_N_MIN_SCAN_CYCLE_MILLIS` prevent a natural stop.
Yes, not using I think the change to use the start scan time is correct, I'll do some tests on my Android 7.x device to verify this has the desired effect for me as well. |
Doing some tests with this today on a Nexus 9 with Android 7.0, I agree there is a problem. Logs before this change. Note an extra scan stop and restart at 12:15:19.451/12:15:19.459, which pushes the number of scans in 30 seconds over the Android N maximum resulting in a blocked scan at 12:15:26.167.
Logs after this change. Note there is no extra scan stop and no blocked scan.
The consequences of this bug (using default library settings) are that there would be a 1.1 second dropout in beacon detections every time ranging/monitoring was started up, or an app moved from the background to the foreground. To make this consequence clear, perhaps the change log description should be "Fix bug causing brief scan dropouts on startup or background-foreground transition due to Android N scan limits" |
Using the prior scan end time to calculate when we can stop the current scan cycle causes an immediate scan stop under two conditions: - this is the first scan cycle - scanning has been stopped for longer than 6 seconds (a more generalized case of the first scan cycle) Notation -------- - current elapsed time in milliseconds: `𝜀` - minimum Android N scan interval in milliseconds (i.e. 6000): `𝛮` - elapsed last scan stop time in milliseconds: `𝛾` - elapsed current scan start time in milliseconds: `𝛼` Preconditions ------------- Under normal conditions the current elapsed time will always be greater than the minimum Android N scan interval of `6000` (i.e. the device has been running for longer than 6 seconds). All values are also assumed to be natural numbers (positive integers including 0). Case 1: First Scan Cycle ------------------------ When the first scan is initiated the last scan cycle stop time will be zero. Since the elapsed time is greater than the minimum Android N interval the bounds check will fail. Given 𝜀 > 𝛮 and 𝛾 = 0, then 𝜀 - 𝛾 > 𝛮. Proof: 𝜀 > 𝛮 𝜀 - 𝛾 > 𝛮 - 𝛾 𝜀 - 𝛾 > 𝛮 - 0 𝜀 - 𝛾 > 𝛮 Thus a stop will happen after the first scan period. When scanning continue it will have to start a new scan, exceeding the five per thirty seconds. Case 2: Long Scan Stopped ------------------------- When scanning has been stopped for longer than 6 seconds we are essentially in a "first scan cycle" situation. This is nothing more than a generalization of the first scan cycle case. Given 𝛾 > 𝛮 and 𝛾 < 𝜀 when 𝛾 + 𝛮 < 𝜀, then 𝜀 - 𝛾 > 𝛮. Proof: 𝛾 < 𝜀 𝛾 > 𝛮 ≣ 𝛮 < 𝛾 𝛮 < 𝛾 < 𝜀 When 𝛾 + 𝛮 < 𝜀 this still holds 𝛾 + 𝛮 < 𝜀 𝛾 < 𝛾 + 𝛮 < 𝜀 𝛮 < 𝛾 < 𝛾 + 𝛮 < 𝜀 ∴ 𝛮 < 𝜀 - 𝛾 ≣ 𝜀 - 𝛾 > 𝛮 So once the first scan period is complete we'll immediately stop it. Solution -------- The simple solution is to always check the scan start time. It will always be true, since only one scan can happen at a time, that the previous stop value is less than the start value. Thus the start value plus the minimum Android N scan time will always be greater than the last stop time equivalent. This guarantees that with normal continuous scan cycling there will be no more than five scans. Caveat ------ However, there's nothing stopping someone from starting and stopping the scans manually. Checking the last scan stop time won't help as normal scanning cycles start and stop scans repeatedly without a delay. This final case requires more investigation as there are several potential solutions but all require significant code changes.
549b656
to
ef48756
Compare
Changelog updated |
Using the prior scan end time to calculate when we can stop the current scan cycle causes an immediate scan stop under two conditions:
The simple solution is to always check the scan start time. It will always be true, since only one scan can happen at a time, that the previous stop value is less than the start value. Thus the start value plus the minimum Android N scan time will always be greater than the last stop time equivalent. This guarantees that with normal continuous scan cycling there will be no more than five scans.