Monthly Archives: March 2015

Strange behavior observed with WiFi direct API

While I was trying to get some data on power consumption of the WiFi Direct API usage, I discovered some strange behavior with it. I had seen earlier that sometimes I’m not really getting services discovered properly. While not knowing what was going on this was getting often a bit frustrating.

While still not knowing exact reasoning why this happens, at least I do have test data that does show that its happening. With the data the N4/N5 in the device id indicates Nexus 4/Nexus 5 device, and the ending part is the firmware version used in the device.

I had the devices going through the testing for around 11 hours, devices were stationary and only running the power test app in them.The environment was my home office, thus it did not have much interference from other devices around.

The logic of the app is to start peer discovery, and once it gets peers changed event, it starts looking for services, and then it just waits until it gets services discovered. Any error situation starts 1 minute timer, which starts peer discovery again. Discovery stopped event also triggers peers discovery start. There is also additional timer to keep the logic running in all situations.

You can find the test application used from Github under DrJukka/WifiTestPower.  And here’s first graph showing the data:

Discovery_all

From the graph we can see that we get loads of Peers Changed events for each Service Discovery start. This is expected, the logic is build in a way that it starts Service discovery only when there is Peer Change event, and we don’t have active Service Discovery going on already.

From the data we can see that the Peers changed events are coming generally all times, and there is no major gaps when we would not be getting them. With devices having Kitkat there is also nice wave pattern on the graph, we’ll get back to that in the end of this article.

Then to see what actually happens with Service Discovery, lets have a look on the data without the Peers Changed events. Then the data looks like this:

Service_Discovery

And what we can see from the data, is that we are getting time periods when we are not actually discovering any services. For me this would be strange behavior, since the environment stays the same, and we have same number of devices around all times advertising their services. But still for some reason the API just stops finding these services.

From the data we can see that Nexus 5 devices having KitKat, the behavior appears to be exactly same with both devices. The time periods when they are discovering services and the time periods when they are not are more-or-less the same.

But with the devices having Lollipop on them, the general behavior is still the same, but the timings are bit off. Also the time periods for different behaviors are longer than with devices having KitKat on them.

All and all, all of the devices are showing behavior where they are having time periods when they are not discovering any services, while still having the Peer Changed event coming, and while starting periodically discovering the services.

Also the data shows that the devices will eventually start finding the services again.

And then lets get back to the wave pattern shown with the first graph. The data also appears to show that when we are actually discovering services, we are getting less Peer Change events.And when the period when we are not getting services discovered starts, we start getting more Peer Changed events.

This can be seen with all devices, though is is less obvious with the Nexus 4 having Lollipop. Not certain if this would help us on finding the root cause of the problem, anyways its still valid observation.

Then lets have a another way on looking into the data, the following graph is showing the cumulative  numbers Discovery starts and actual Discoveries over the 11 hour period.

Discovery_cumulative

Again Nexus 5 devices with Kitkat are doing it in sync, and devices with Lollipop are doing it differently. But the point what this graph shows clearly, is that the Lollipop devices appears to be making only half of the amount of Discovery start events, when compared to the devices having Kitkat.

Also it shows that both Lollipop devices are making about the same amount of Discovery starts, but as the Nexus 4 had longer period it was not getting any services discovered, it gets only 2/3 of the services discovered, when compared to Nexus 5 with Lollipop.

Lets see if we find any good reasons for the behavior of not Discovering services, or should we go finding a workaround solutions, meanwhile I’ll continue on trying to get the power consumption data for the API usage.

 

Wifi pairing

In the Wifi direct, connections without User interaction article I suggested that you could teach each device, all “Known groups”, so they never ask for the dialog again, thus enabling the communication via Wifi Direct automatically without any further user interaction requirements.

I also noticed with later tests that, if two devices have had communications before, and one of them has accepted the connection. Then one of these devices is set as group owner and other as client. And both ends have saved the data for the “known groups” for this linking.

Then, it appears that it does not really matter, which device starts connection process, they will end up having the same Group owner & client, and thus no further acceptance dialog is shown.

This in general would be good, unless there would be more devices, and thus chances that the client device in the first pair also being selected as Group owner for other pairings.

Thus to make the pairing really work, we need to be able to make both ends to work as group owners. Luckily the seconds method in the Wifi direct, connections without User interaction article provides the solution for this problem.

If we do use the createGroup() fucntion from WifiP2pManager to create a group, it does indeed create a group, and make the device group owner for the group. Then anybody connecting that device, would be automatically set as clients.

To proof that this works I did create Wifipairing example, which shows how easily this works. Basically you just start the app, and click the device name appearing in the list to make one-directional pairing, and then you repeat the process from other device to make the pairing work both ways.

As noted in earlier tests:

  • The “Known groups” are not application specific, but device specific, thus any app can make the “pairing” and others will benefit from it.
  • The “Known groups”  information is saved in a way that it survives device reboot.

Thus based on current understanding, this would be really a viable way on “pairing” Wifi-direct devices, and thus allowing us to use Wifi- Direct in use case where the connections must be handled without user interaction.  Downside being that each device must be paired before the automated connections can be made.

 

 

 

Improving the Wifi-direct applications logic

In the Initial Investigation with Wifi-Direct, I had a simple logic which did go through following states:

  1. Discover service from other device
  2. Connect to the service on the other device
  3. Exchange data
  4. Disconnect from the other device
  5. Start discovering the service

While this is indeed good logic, the implementation I have come into realization that the implementation did indeed have some flaws. And some of the flaws are generating some ill effects as well. While saying that the design was bad, it was illustrating one point really nicely. that is: Badly designed WiFi-direct apps can mess up the service.  While we would change the design, there is always a risk that some other app installed into the device, will behave badly, and if they do, they will negatively impact your app.

Most of the issues identified in Initial Investigation with Wifi-Direct were happening with Service discovery step. And easiest way to get rid of these problems, is to make sure you call to start any discovery, only when you really need it. Here’s some tips:

  1. just call discoverPeers() once, and only call it again when you are informed discovering process being stopped via the WIFI_P2P_DISCOVERY_CHANGED_ACTION. This ensures that the service wont get additional calls for re-activating already active discovery.
  2. Implement a logic which calls discoverServices() only once, and then implement logic that waits for all services being discovered and submitted to your app. (simple time-out-timer for 5 seconds, which you would reset each time you get onDnsSdServiceAvailable() called, will do fine).

In reality this means that peerdiscovery is started once when discovery process is started, and then only when the service tells that it is stopped. Or additionally, once you have discovered all services, and found out that none of them are interest to you preventing you on moving to next step.

And for service discovery, you would need to make sure that:

  • requestPeers() is only called once.
  • Start discovery for services, only if there is peers available.
  • make sure that, you call discoverServices() only once, even when onPeersAvailable() would be called multiple times.
    • It was noted during tests that even when requestPeers() was called once, the  onPeersAvailable() migth in some cases be called as many times as there are peers available. Even when the list of peers stays same with all calls.

With these simple changes I did not need the workaround for where we had to switch Wifi off and then back on. Now if the discoverServices() would fail, then we would simply wait untill the WIFI_P2P_DISCOVERY_CHANGED_ACTION event is received, and after it, the discovery process is re-started. Observations suggest that issues causing the errors, are usually solved by then already. And that the time lost there is usually around one minute.

Some tests though brought up a possibility that we would need to have a additional timer, which would start the peer discovery in a case that we had several devices nearby advertising their services, and just when we started service discovery, all of them stopped advertising (due the logic for connection status changes). There have been observations that the device gets confused and never gets the onDnsSdServiceAvailable() nor the WIFI_P2P_DISCOVERY_CHANGED_ACTION called, effectively leaving the device in a state that it will never attempt to make any connections itself.

Additional design changes were the timings when we do advertising and discovery. with new design:

  • We stop advertising as soon as we notice that we are connected as client (since we can not accept any incoming connections)
  • We stop searching as coon as we start connection attempt (since we have selected a peer already, we don’t have need to search for others right now)

With these design changes I also separated different parts of the logic in to separate class implementations. Basically to have the logic working outside the class implementations, as well as to get the implementations more-reusable in different contexts.

The example with this new improved logic is available at the Github under DrJukka/P2PChatTest2.

 

 

Wifi direct, connections without User interaction

As  I wrote in the UX with Wifi Direct: The connection acceptance dialog article, there is acceptance dialog, which requires User interaction before any data can be exchanged between the devices.

This is not really ideal situation with Thali project, in which we would actually require the connections do be established fully automatically.  To fix this I would have two solutions which might work, depending on requirements:

  1. Teach each device, all “Known groups”, so they never ask for the dialog again
  2. Modify the communications to be handled in a way that no dialogs are ever shown.

For the first fix, we could make an app, which you would start and select which mode it would work (either Advertiser who waits for connections, or a devise that initiates the connecting  process), and the app would then do connection and once its verified to work be exchanging some data, they would revert the roles and do new round. While running both devices should have the dialog shown once, and user would then need to click the accept button to store the information in “Known Groups” settings.

This of course would be required to be handled with each device we can potentially have connections between, and would need to be re-done , in case the device is cleaned.

The second fix would require doing the connection a bit differently, in essence the steps are:

  1.  Use createGroup() fucntion from WifiP2pManager to create a group. This creates an access point, with random SSID and password.
    • Start same time a server which accepts the incoming connections required for your service
  2.  Once the access point is ready, you’ll receive WIFI_P2P_CONNECTION_CHANGED_ACTION. Then fetch the group information to get the SSID & password
  3. Create local service to advertise the access point. You can use the local instance variable for giving the access point information (SSID, password & IP-Address)
  4. Do Service Discovery to find any peers nearby advertising their access points. Once found, see what SSID, password and IP-Address are used with there.
  5.  Use WifiManager for forming the connection (instead of WifiP2pManager )
  6. Once the Connection is established,
    1. Stop advertising for the access point.
    2. Remove the access point
    3. Stop searching for additional access points
  7. Make connection to the IP-Address you got from the service you discovered in step 4.

Here’s coupld of pointers to remember with this approach

  • Its likely that all devices get same IP address when they form the access point, and thus do remember to remove the access point in step 6, otherwise you’ll communicate with your own server in step 7.
  • With Android devices, you can have connection only to one WLAN Access point, thus if you had any active WLAN connections, they will be disconnected when you start connecting in step 5.

I made simple example showing how the fix number two works, and you can find it from Github under the DrJukka/MyWifiMesh. Do note that its not fully finalized, and is just used for proof of concept for further development.

UX with Wifi Direct: The connection acceptance dialog.

As the goal for my investigations would be to find suitable solutions for the Thali project android issues for the P2P are discussed in Exploring Android to Android P2P page, the Wifi direct does have one annoying feature that potentially makes the API rather unusable.

This is the requirement for showing the acceptance dialog. Basically each group linkage has to be accepted by one side of the connection. The selection of who the accepting party is, is solely determined by the fact that who started the connection process. The dialog is then shown in the device which the connection is made to.

Also note that the dialog is shown in both ends on some point, that is if the device which starts the connection process between these devices changes in some point of time.

To explain this a bit better,Lets assume we have a  new app installed in three devices, which have not formed any connections between them beforehand. Then lets assume following steps:

  1. I’m hanging around in cafe area when Mike comes around, and I start connection to that device and when the connection is established, I’m selected as Group owner.
    • In this case Mike had the dialog showing,  i.e. the dialog was shown in  client side.
  2. Then Jenny comes around and starts connecting to my device
    • Now my device shows the dialog, i.e. the dialog is shown in Group owner side
  3. I’ll leave the place, and thus both Mike & Jenny are getting disconnected, and then they form a connection between each others device, and  Mike gets to be Group owner.
    • The Connecting process was started by Jenny, thus it was Mike’s device which showed the dialog this time.
  4. I’ll come back and find Mike’s device as Group owner, thus my device start creating a connection to Mikes device
    • Mike’s device is now showing dialog for accepting my connection request.

So My device had dialogs twice, one for Mike, and one for Jenny. Mike had also the dialog shown twice, once for me and once for Jenny. And Jenny never saw any dialogs.

Thus if I would try connecting to Jenny (or Mike would) , then she would have the dialog shown for both of us. And If we would get these cases covered, we wouldn’t see the dialog in the future.

Or would we ?

One nice feature with the WiFi direct is that the “Known Groups” information is saved, and if you go to settings and dig under the WLAN, you can find the stored groups information in there.

The Information is stored there in a way that I so far only seen them disappear, if I explicitly go and delete them, or if I do factory reset for the device.

Also since I have not seen any documentation suggesting any automated cleaning, I would simply assume that the data stays there, unless they are cleaned by either of the mentioned ways.

All and all, do note that the “Known group” information is stored in both ends and if it is cleared in either end, the connection will be showing the dialogs again.

For example, in the example case, in the end, all devices had 2 items stored under the “Known group”, even Jenny who did not have any acceptance dialogs shown to her. And if Jenny would clear the items from her device, then the dialogs would be shown again, if she would attempt to connect Mike’s or My device in the future.