How does Apple's proprietary technique for background GATT service advertising on iOS work?
According to Apple's documentation, when an iOS app using CoreBluetooth to implement a BLE peripheral is in the background, service UUIDs are no longer advertised, and instead are put on a special "overflow area":
Any service UUIDs contained in the value of the CBAdvertisementDataServiceUUIDsKey key that don’t fit in the allotted space go to a special “overflow” area. These services are discoverable only by an iOS device explicitly scanning for them. While your app is in the background, the local name isn’t advertised and all service UUIDs are in the overflow area. -- developer.apple.com
But what is this "overflow area"? How does it work?
I set up a bluetooth sniffer and captured the BLE data exchange, but failed to find any communication of this Service UUID. A second iOS device in the foreground was repeatedly able to successfully discover the service advertisement on the backgrounded iOS device, but the packet capture never once logged the Service UUID.
So how does this work?
If I can figure out how it works, I would like to try to program an Android device to use the same process.
The Overflow Area is a manufacturer advertisement emitted from iOS devices when at least one iOS app is advertising a CoreBluetooth service from the background. It looks like this:
ff 4c 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80
The ff
signifies a manufacturer advertisement, the 4c 00
bytes correspond to Apple’s assigned manufacturer code of 0x004C by Bluetooth SIG. The 01
identifies this as an overflow area advertisement. The last 16 bytes (128 bits) are a hashed bitmask of services advertised.
Each service UUID you advertise will cause exactly one of those 128 bits to be set to 1. There is a one-to-one mapping between a service UUID and the bit position it sets in this bitmask. This is consistent across iOS devices. Converting a service UUID to a bit position in the bitmask is some proprietary Apple hashing algorithm.
Because there are a huge number of possible 128-bit UUIDs – 2^128 (about 10^38) – multiple service UUIDs share the same bit position.
Since many service UUIDs share each bit position in the overflow area bitmask, collisions are inevitable. iOS will give a scanning callback a the colliding but different service UUID. This won’t happen often. But programmers should realize that they may scan for their service only to get a callback for detecting a backgrounded iOS device advertising a completely different service that just happens to collide in the overflow area’s bitmask.
Interestingly, the overflow area can be manipulated to enable two backgrounded iOS apps to exchanged data in the background. See my blog post for more info.