Monthly Archives: May 2015

Bluetooth P2P sync for Android using insecure sockets

I had a task to build library which could be used for p2p data exchange in situations where there were no data-networks available. Also the data exchange should if possible be handled automatically as soon as device which is implementing the service is found to be nearby, this all should also happen without any need for user interaction. The implementation should also work with normal devices, with firmware versions generally available and without rooting the devices.

In the beginning of the study three different technologies that could be used with android devices for the use case were identified to be:

  • Bluetooth
  • Bluetooth Low Energy (BLE)
  • Wi-Fi Direct

I have been writing about the Wi-Fi Direct parts, and will be writing more until I get the task finished with it. And with this article I’m concentrating on the Bluetooth parts.

The BLE then offers advertising the service and locating it without any need for pairing the devices. Unfortunately with android device, the peripheral mode required for handling the service advertising is only available with Android Lollipop versions, and only if the device hardware also support this feature. With currently available devices, the support is not really wide, thus this technology was deemed not to be feasible at this point of time, though I’m planning to get some work done with it later on.

The standard Bluetooth technically then has a two phase life cycle. In the first phase one pairs two devices together. In the second phase one discovers when a paired device is nearby. The pairing requires users of both devices to be close proximity and both device users to accept the paring, and thus it requires user interaction.

By default in Android when switching a device into discovery phase one has to get approval from the user and then a countdown begins during which time the device will make itself discoverable to other Bluetooth devices. This means that also the discovery phase cannot be fully automated, and when enabled it would only work for limited time period.

Because of the limitations listed for the standard Bluetooth, the implementation used in the case study is utilizing Android specific implementation of insecure Bluetooth sockets. This approach has one major advantage when compared to standard Bluetooth, which is that it does not require any device pairing in any stage of the data exchange. Which means that if we know the target device Bluetooth address, and the target device is listening for incoming Bluetooth connections, then we could implement the data exchange without user interaction.

As it was mentioned in the beginning the normal way on exchanging data is to first discover the peer, and then open data channel to exchange data. With this implementation the discovery and data channel establishment is handled in single step, and to be more precise the actual discovery step is omitted, and we simply opportunistically try to establish data channel between devices, and once we succeed with the data channel establishment, we then also have succeeded discovering that the peer is in our vicinity.

So in the beginning each device must have the list of Bluetooth addresses of the peers it wants to communicate with. The list can be delivered manually, by email etc. Or as with the example by discovering peers nearby by Wi-Fi-Direct peer discovery.

Then when the application is started each application must start listening for incoming connections. And once connection comes in, it saves the data into a database, so the device user can see them later on. And also it starts listening for more incoming connections, thus keeping the listening on for all times.

Then when the user schedules a message, it’s simply put into a database and marked as non-delivered. Then a scheduler is started, which will read the database items marked as non-delivered, put them in an array, and start looping through the array list.

In each loop the scheduler tries to establish connection to the Bluetooth address for the message, and if it fails, it then moves to next message in array list. If the connection establishment works, then the data for the peer is sent, and the item is marked as delivered in the database and removed from the array.

The scheduler continues the loop until it has delivered all of the messages marked as non-delivered.

There is a full example illustrating the approach available at: DrJukka/BtInsecureSync and the following video shows how you can use it.

The implementation itself is really simple, basically the challenges with the method was that originally there were no data on using the API in this way for extended periods. Thus to determine the feasibility of the API for any given purpose we needed to get ideas at least for following performance characteristics:

  • how fast we can do the discovery
  • How long much does battery does the discovery consume.

Both characteristics were measured using one test application, in which we had one address and we are continuously looping the search with it. Timing for each discovery round was measured, and to determine the battery usage, the test was run from full battery till the device battery run out. When doing the tests devices were not doing anything else, they did also not have any SIM cards and no other network activity, and thus in general during the tests, we can assume that the only part that consumes battery in the device, was the test application.

The test application can be downloaded from DrJukka/BTPollingTest.  The test application was run on background with 4 test devices over a period of time, which after the values for minimum time, maximum time and average time spend on one polling round as well as the average battery charge drop percentage over an hour were measured. and the values are shown in the table below:

N5_501 N4_501 N5_444 N5_443
Min /sec. 5,13 5,16 5,12 5,12
Max /sec. 5,23 5,22 5,20 5,18
Average /sec. 5,15 5,17 5,13 5,13
 
Bat%/h 1,49 2,64 1,45 1,32
runtime/h 67,26 37,87 68,97 75,53

 

The N5 stands for Nexus 5 devices, and the N4 for Nexus 4, the 3 character number then indicates the firmware version (for example 501 is Lollipop 5.01). From the data we can conclude that one polling rounds takes about 5.2 seconds, thus we can in maximum get 11 rounds done in one minutes time, which in reality means that if we have 11 messages to deliver, we need to spend at least one minute of time near a target device, in order to be sure it will be discovered, and if we just have one, then we should be able to discover the device within 5 seconds from the time we come into the vicinity of it.

The run time is calculated from the battery usage data gotten with the tests, in it all devise were without SIM and without Wi-Fi, and without any other apps running, thus the power consumption should come only from the running the app and the HW it requires.

With the Nexus 5 test devices we are getting around 70 hours of run time for the app, with Nexus 4 it’s about half, with all devices the consumption would in general be in a level that the application battery usage should not be big issue when it is run in normal device with other apps running same time.

The sample implementations did show that the method indeed is usable, it can be used in situations where we need automated syncing with peers without any user interaction, provided that the following rules apply:

  • We can get Bluetooth-Addresses of the peer devices stored in the device
  • The number of peers to send messages is not high, i.e. less than 11 at any time (unless we can accept higher discovery time)

Getting the discovery work continuously

With earlier tests we have seen problem arising with the services not being discovered for some time periods. The patter where the services are being discovered normally, and when they are not being seen (even though we know the neighboring devices are advertising their services) appears to be repeating with different patterns on different firmwares.

Earlier we have seen that toggling WiFi first off and then back on do help recovering on some errors, while we also have seen that doing it extensively could also lead to situation where I could only assume that the WiFi Direct service has crashed on the device.  Also I have feeling that often with this API, its safer to prevent error situations than trying to get out from them.

So I wanted to try out if we could get the service discovery to work continuously by toggling the Wifi on/off. And with the previous issues noted, we should try doing it before we get into the situation where services are not being discovered anymore. Also we should not do it too often, to avoid getting in the situation where the WiFi direct service itself would crash.

For the tests I decided to try 30, 60 and 120 minute intervals for the toggling. And also to check how the toggling effects the usage, I also had ‘normal’ discovery test done, in which the WiFi was continuously on.

With tests the batteries were changed full and then the 4 devices were left to run until their batteries were empty. The test data were logged into a file every 20 minute. Lets first look into the services discovered:

Services_combined_summary

From the graphs we can easily see that with ‘normal’ test run, we get repeating time periods when the count for services discovered is not increasing, meaning that with these periods the device is not discovering any services.

And if we do the WiFi on/off toggling we don’t see these time periods on the graphs, thus we could say that this method works, and produces the wanted outcome.

By just looking the data, the 120 minute toggling interval also appears to produce slightly less discoveries, that 30/60 minute intervals.

Then lets see this from the battery consumption point of view. And the following image shows the graphs for different tests:

Battery_combined_summary

Again, the data would suggest that 120 minute interval would be a bit worse than the 30/60minute ones, but the difference is not that significant.

To conclude these tests, I would say that

  • toggling WiFi off/on, does appear to work on fixing the Service discovery problem we been having.
  • doing the toggling every 30 minutes appears to be safe.
  • 30-60 minute toggling interval appears to produce slightly better performance than doing 120 minute intervals.

Thus for real world usage, you could indeed use this method, though you should also do it in a way that interferes with the users data usage as less as possible, thus a logic which would check current network usage should be combined to determine the actual interval for toggling, anything between 30-90 minutes should be fine to use.