In the Initial Investigation with Wifi-Direct, I had a simple logic which did go through following states:
- Discover service from other device
- Connect to the service on the other device
- Exchange data
- Disconnect from the other device
- 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:
- 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.
- 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.