So my question came up looking an the console output of some iOS 7.0.x devices via iPhone Configuration Utility the other day. I was puzzled to see several indications that the WiFi daemon registers WiFi rssi activity out of the blue for no apparent reason (no background apps active / push messages pending and so on). These all appear as coupled records in the console in the form of:
Mar xx xx:xx:xx iDevice wifid[xx] <Notice>: WiFi:[406330748.823677]:
Mar xx xx:xx:xx iDevice wifid[xx] <Notice>: Too frequent(1.822344 secs) rssi event from driver
Mar xx xx:xx:xx iDevice wifid[xx] <Notice>: WiFi:[406330748.895756]:
Mar xx xx:xx:xx iDevice wifid[xx] <Notice>: Too frequent(0.835468 secs) rssi event from driver, ignoring
...and so on. What got me worried is that the lines above are duplicated every second or so and appear to never end.
Now I'm no programmer in any kind of form, but knowing some of the basics of UNIX and all I've managed to conclude that the WiFi daemon takes up substantial CPU time as shown in an top breakdown using the terminal, which in turn would suggest that this may (or not) be a reason I've also been experiencing poor battery life on some of these devices as of late.
Next up I would obviously ask you all if anyone's familiar with the behavior noted above and if so what would be the source of this "noise"..
The Short Answer
At least one app is repeatedly querying WiFi for signal strength, and it's chewing up a lot of battery life.
The Longer Answer
1. What is RSSI
RSSI stands for Received Signal Strength Indication. It is a measure of the power present in a wireless signal. RSSI queries are made each time the wireless driver tries to determine reachability. You can learn more about it here:
http://en.wikipedia.org/wiki/Received_signal_strength_indication
2. Why So Many RSSI Events?
In this case, a WiFi RSSI driver is caused by querying for reachability - basically, trying to find out if a wireless connection is available.
There are numerous cases of poorly-written apps querying for reachability/connectivity every few miliseconds. You can find examples that query too often all over the web. I'll just put up one here:
http://forums.coronalabs.com/topic/33356-check-for-internet-connection/
3. Impact on Battery Life
Apple's documentation is very explicit about radio usage. The more you use the wireless radio in the phone, the shorter the batter life. They go so far as to say:
Minimizing radio usage is especially important when developing an app for an iOS device, because radio usage has an adverse effect on an iOS device’s battery life.
(Source: https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/BestPracticesForInteractingWithARemotePeripheralDevice/BestPracticesForInteractingWithARemotePeripheralDevice.html)
4. What You Can Do About It
There are several steps you can take if this is shortening your battery life:
Use the logs to determine which apps are abusing the radio and remove them.
If it is an app you have written, carefully look for any repeated calls to the web, especially reachability or signal strength calls.
If the app is not your app and you must keep it installed, use airplane mode when you can to conserve battery (the LEAST desirable option).
Hope that helps!
I'm effectively copying my reply from jailbreakqa.com in http://www.jailbreakqa.com/questions/256971/too-frequent-rssi-event-from-driver
"Being plagued by other issued alongside the aforementioned rssi thing this time around I semi-restored back to iOS7.1.2 and set up the phone as new with the same AppleID as suggested by theiphoneguy above (keeping a backup of my SMS and photos database). Surely three days in the fresh install already the previous rssi issue seems to be now gone for good and I'm enjoying a rather clean activity console with not many things populating it apart from the usual noise..Only considerable downside to it was that I had to waste a full day bringing the system back to speed with the installed tweaks and settings as I am now on a complete 'fresh' install with no references back to the old backups...
...that and the fact that whatever happens I can't seem to be able to make iCloud tabs work (deleted and reisntalled iCloud, disabled safari within iCloud and restarted it to no avail.). In all this seems to have made my device quite a bit 'snappier', too (probably since my old backups dated back to iOS2 :D )...quite pleased with current status, however quite a bit of hassle, can't really suggest that anyone goes down this path.. :/ "
I know this does NOT qualify as an answer per-se, but may serve as evidence for others having the same issue in the future.
Related
We are developing a device which communicates with our iOS/watchOS apps via Bluetooth LE and has to stream a lot of sensor data for an extended time period (hours). Everything works fine under iOS 15.x, but we've found out that iOS 16 betas (and the RC) changed something in the negotiation process: previously we've used 15 ms Connection Interval, but iOS 16 (and watchOS 8) most of the time negotiates 24 ms, which is too wide for our bandwidth. The long connection interval causes packet loss (9-33%), and after 3 failed retries (3x30 sec) our hardware drops the connection.
I've checked all forums and documentation available but didn't found any indication that something changed. Is there any new parameters we can look into to fix this issue?
EDIT: Changed 30 ms to 24
You've probably set both Interval Min and Interval Max at 15ms. Apple explicitly says that this may caused devices to negotiate to 30ms (see section 41.6 Connection Parameters):
If an accessory requests both an Interval Min and Interval Max of 15 ms, some devices will scale the interval to 30 ms to balance power and performance constraints.
Basically, asking for "as fast as possible, no margin" translates into "yeah, everyone asks for that, how about moderately fast?"
However, you may ask for a faster CI if you include HID:
If Bluetooth Low Energy HID is one of the connected services of an accessory, a connection interval down to 11.25 ms may be accepted by the device.
Though I believe what iOS 16 is doing exactly matches Apple's spec (they always said that 15ms could be negotiated to 30ms), you should still open a Feedback+DTS to discuss the impact on your product and use case. Sometimes these things are by accident, and sometimes they're experiments that get rolled back.
We had the same issue with our product. We used a 7.5-15ms interval that was accepted by iOS15 & below, though it didn't meet the Apple Design Parameters (we thought we could get away with it since it was working). We had to change it to 15-30ms for the issue to be resolved, though now the amount of time it takes to transfer data for Androids has doubled.
As Rob mentions in this thread, it seems that for iOS16.0, Apple decided to strictly follow their guidelines and not allow anything outside those "set" requirements, even though they allowed it in the past. However, it seems that Apple has reverted back to how iOS15 was operating with iOS16.1. (There is no documentation that says this though - just know through testing)
If you need a quick fix right now, if you have users, have them update to iOS16.1. Your device should operate as it should when it used to run on iOS15.
For a long term solution, I would follow Rob's suggestion.
I know the answer is nominally "no", but I mean really—what if the app goes into the background (with BTLE background processing enabled)? For 24 hours? Across an app update?
Under the heading "Reconnecting to Peripherals", this Apple documentation describes a reconnection workflow that first tries to reconnect to previously paired peripherals found via retrievePeripheralsWithIdentifiers: but then starts scanning again if you fail to connect. How do you know when to give up on connect-ing to a previously found peripheral if there is no formal timeout? How do you know when to start/keep scanning if the idea is to re-connect to a previously found BTLE device whenever you move back into proximity to it, without the user necessarily interacting with your app?
Also, a note further down that page says that some BTLE devices might invent a random identifier for themselves every time they're powered on, so even though you find some previously paired peripherals from retrievePeripheralsWithIdentifiers: you might not be able to connect to them as their names have changed. Do any BTLE devices do that in practice? That's nuts!
This is a tricky one to answer. The CoreBluetooth framework itself does not have an official timeout on connect requests. In fact it will try to connect the peripheral for as long as possible. But how long is that?
Well, unfortunately this is not something that is very well defined. You can be pretty confident that the connection will not time out while the app is in the foreground, but as soon as you involve connections in the background then things are not so funny any more. Obviously, like you mention, the pending connection will not remain after a phone reboot, etc.. which is fine since no user would expect the app to still be running after a reboot anyway. Regarding long running pending connections, you will find in Apple’s documentation that they tell you to opt-in for State Preservation and Restoration in order to make sure that the pending connections are properly kept while the app is suspended and eventually terminated. This would be good if it worked as advertised, but unfortunately it does not. After many years of working with this I have found that it is nearly impossible to get a reliable background pending connection on iOS. I have reported many bugs on this topic but so far none have been resolved.
There are a few issues in particular that I think you should pay extra attention to:
State Preservation and Restoration will completely stop working if a Bluetooth-state-change event happens while your app is in the terminated state. This essentially means that if the bluetooth chip gets reset for any reason (ex by toggling bluetooth/flight mode/etc..) then your app will never be relaunched again by Core Bluetooth whenever the peripheral is advertising within range. The reason for this is because all pending connections that have been set by your app will be cleared whenever the bluetooth chip is restarted. The problem with this is that your app will not be relaunched to be notified of this change, so the pending connections will never be recovered. So your app will think that the peripherals will connect, while in fact they will not. To me this one is the most serious issue and it alone makes CoreBluetooth extremely unreliable.
Sometimes the framework gets ”stuck” in a bad state (possibly by an internal race-condition or similar). This can happen randomly, but you can pretty easily reproduce this by calling connectPeripheral immediately in the didFailToConnect or didDisconnect callback. When this happen the ”connection state” property is set to “connecting” when a pending connection is in fact not set. To avoid this I have found that you should wait at least around 20ms before connecting, for example using a dispatch_after or something.
The framework internally uses XPC connections for interprocess communication in order to deliver bluetooth event. On some occasions this will break for whatever reason and the connection will be lost. I don’t know why this happens, but whenever it happens state preservation will stop working and you will manually have to relaunch the app to recover from it. Sometimes I manages to catch this in the device sysdiagnose logs...
Using an iPhone 7 and at the same time having an Apple Watch (paired the phone) will completely break all reconnects from behind the lock screen in case the Watch is not currently connected (out of range/flight mode/low battery/or any other reason). This is particularly bad since it was introduced recently! But it looks like the Apple Watch for some reason has "priority" over other bluetooth peripherals.
These are from the top of my head, but there are other issues as well. Regarding random addresses, most often these peripheral use so called ”random resolvable” addresses. This means that they appear random but in fact they can be resolved using an IRK (Identity Resolving Key) which is usually shared during initial bluetooth bonding. Devices that use completely random addresses are to my knowledge not very common.
I am designing an iOS framework to handle multiple BLE devices (all of the same kind). Everything is working very well at the moment, except one thing:
The client wants a list with available devices. But how can I detect when a device, that has been discovered in the past, is not available anymore?
Another problem occurs, when I try to connect to a device that is not available anymore. Documentation says: Connection attempts never time out and
And yes, I never get an error via didFailToConnectPeripheral.
I did some research but couldn't figure out how handle these problems via CoreBluetooth properly. So I developed my own solutions, but I am not sure if that is the right way (or at least a good way, cause there may be several ways to do it).
1. Detecting devices that are not available anymore
I scan with
[_centralManager scanForPeripheralsWithServices:services options:#{CBCentralManagerScanOptionAllowDuplicatesKey: #(TRUE)}];
so I receive advertisments all the time as long as a device is not connected. I check with a timer that the advertisement reoccured in a given time interval (large enough corresponding to the devices ad interval). If the advertisement didn't occur in the interval, I remove the device from the list.
2. Detecting connection timeout
Well, that's a pretty easy one I think. I use my own timeout function and cancel the connection request if the timer expires.
If somebody ever came across these problem, I would be very interested in your opinion and/or your solution of course.
UPDATE 2014-12-17:
In the meantime I worked on my own solution using timers and it seems to work pretty well.
Connection timeout is straight forward. Simply set a timer to 5 seconds or whatever you think is good for you. If the timer expires and the device did not connect, simply cancel the connection and tell the user that there was a problem.
Detecting devices that go out of range was a bit trickier. For every discovered device I start a timer that fires after double the time, the device sends advertisements. If the device does send another advertisement till the timer expires, it probably went out of range or was turned off or connected to another device.
I don't want to answer my own question because I hope that maybe Apple will one day take care of those problems.
The correct way to determine whether a device is available is to store the peripheral identifier value. Before you attempt to reconnect, call retrievePeripheralsWithIdentifiers. However, this still does not guarantee that the device will be in range by the time you attempt to connect!
Connection attempts do not time out at the OS level, and this is explicitly documented.
Some apps may need to use the Core Bluetooth framework to perform
long-term actions in the background. As an example, imagine you are
developing a home security app for an iOS device that communicates
with a door lock (equipped with Bluetooth low energy technology). The
app and the lock interact to automatically lock the door when the user
leaves home and unlock the door when the user returns—all while the
app is in the background. When the user leaves home, the iOS device
may eventually become out of range of the lock, causing the connection
to the lock to be lost. At this point, the app can simply call the
connectPeripheral:options: method of the CBCentralManager class, and
because connection requests do not time out, the iOS device will
reconnect when the user returns home.
I have an app that uses LocationManager. For a while I was using Significant Location Change notifications. As I read the documentation, I believed 2 things to be true:
They did not really consume any extra battery because you were basically telling the phone, 'just give me knowledge you already have.'
When the app was off, the notifications stopped.
Once I introduced that, I got a lot of emails from people accusing me of burning up their battery. So I took it out.
Got an email yesterday from a fellow showing me that the location arrow in Settings/Privacy was still purple, even when the app wasn't running. That's also true on my phone.
I can only think of two possibilities:
The registration for significant change notifications is still in tact, despite upgrades to newer versions, etc.
Or, one time the app crashed while the location manager was on and it was never turned off.
2 seems pretty far fetched, as I would think there would be a ton of that happening potentially. I was kind of disappointed that there's no way in Instruments to see what the system believes its obligations to the app are, and when they have been in effect since.
It would be nice to see what delegates are active for an app, even beyond the app running actively.
From what I know about the significantLocationChanges, they work along the same principles as the regionMonitoring. If you have users complaining about battery life, they are likely getting burned by something else. -significantLocationChanges uses fewer items for location than -regionMonitoring does. I believe they are strictly cell-tower related. They may use Wifi detection as well, but they don't advertise it.
Also, the location monitoring will persist even when the app has been killed and between updates and upgrades. I don't know how the app will behave if you upgrade the app and remove the delegate methods while the app is still monitoring for them. My guess is they will get orphaned out there, the callbacks would try to notify your app but the methods are gone and will be ignored. Just a guess, but might be worth testing out. It might be worth leaving those in or a method that will remove all location monitoring. Then remove all that in a later update just to make sure nobody still has any active location code out there.
I've encountered a pretty large issue and have been trying to find a solution for 2 months now with no luck. I've submitted it as a bug, ( https://bugzilla.xamarin.com/show_bug.cgi?id=4910 ) but was hoping maybe someone here could shed some light on the cause of the problem, or suggest a work-around.
In a nutshell, to encounter the error:
Create a basic .Net socket connection between two devices
Create and initialize a GameKit.GKSession object on a least one device.
What occurs is the transfer of the data on the .NET socket becomes erratic and too slow to be usable. I've performed many tests across different devices (see link below) and it affects all of them (iPad 3 affected the least). I've tested it between an iPhone and a Windows PC and it still occurs. MonoTouch's GameKit code is somehow affecting the Socket code.
As you can see from the spreadsheet, speed drop from a few milliseconds to send 1 MB to several minutes to forever.
As soon as the GameKit.GKSession is set to null, any backedlogged data on the socket flows freely again and the sockets act normally once more.
Sample Windows and iOS/MonoTouch Apps demonstrating problem: https://dl.dropbox.com/u/8617393/SocketBug/SocketBug.zip
Test results across different devices (PDF Spreadsheet):
https://dl.dropbox.com/u/8617393/SocketBug/SocketBugTestResults.pdf
This issue seems so hard even Apple decided to circumvent it: http://developer.apple.com/library/ios/#qa/qa1753/_index.html#//apple_ref/doc/uid/DTS40011315
The revealing sentence is this: "This change was made to reduce interference with Wi-Fi."
To assist with anyone that comes across this problem, the issue only manifests itself when the GKSession.Available is set to true. This is required for the device to be discoverable, but not to maintain a connection. With this in mind, a temporary work-around can be used where the GKSession.Available is only set to true when required, and set to false as soon as the connection has been made.
In my scenario, I have a socket connection to the server on both devices. I use this connection to send a message from device A to device B, asking it to become discoverable via bluetooth for the next 10 seconds. As soon as the message is sent, device A begins looking for device B and connects as soon as it finds it. Once the connection is established (or 10 seconds elapses without a connection), device B turns off discoverability and the socket behaves as normal.
In my circumstances, this is an acceptable (pending no real fix) workaround to the problem.