Closed fmeum closed 3 years ago
Wow. Thank you for the detailed investigation. I haven't touched the code for a while, but it seems that it's worth implementing these fixes. I'll get to it shortly. Thanks again!
This made a big difference for the WearAuthn watch face complication (which can be unlocked from the phone app), which previously called register and requestConnect right after each other. The fix described above is included in version 0.9.16, so if you want to experience the difference it makes, you can give it a try.
Gate the requestConnect call on both onServiceStateChanged and onAppStatusChanged having fired positively by having each listener check whether the other has already fired and only then calling requestConnect.
Note that onAppStatusChanged(true)
can only be called after onServiceStateChanged(non-null proxy)
, since that's where hidDeviceApp.registerApp(proxy)
is called.
So, I'm going to go for a simpler fix on my side. :)
Gate the requestConnect call on both onServiceStateChanged and onAppStatusChanged having fired positively by having each listener check whether the other has already fired and only then calling requestConnect.
Note that
onAppStatusChanged(true)
can only be called afteronServiceStateChanged(non-null proxy)
, since that's wherehidDeviceApp.registerApp(proxy)
is called. So, I'm going to go for a simpler fix on my side. :)
Thanks for confirming this. I wanted to play it safe given that I only have a single watch to test on, but that seems reasonable. I will simplify the code in a future release.
So, I've submitted f2ac55e4fc749860e5227810f0aa91b7d3d68850 - have a look. It should probably be enough.
I like your approach for its improved encapsulation. I will see whether I can adapt this for WearAuthn.
During the investigation of Bluetooth connectivity issues reported against WearAuthn, I took a deeper look into the Bluetooth HID backend more or less shared between WearMouse and WearAuthn. This lead to https://github.com/FabianHenneke/WearAuthn/commit/fe96b23b9ed90860bf418f5fe8d760d2cd147358, which appears to fix at least some of the issues by removing a source of non-determinism. Since a similar change could be implemented in WearMouse and might help prevent some edge-case bugs, I briefly want to describe my findings here.
The cause of the non-determinism is the lack of synchronization between the call to
HidDataSender.register
here and the user-initiated calls toHidDataSender.requestConnect
here and elsewhere in that file. Usually, since this requires the user to tap at least two buttons, theHidDataSender
will be ready to receive connections by the time the user requests a connect, but this is not certain and failed in slightly different scenarios in WearAuthn.Based on my experiments,
requestConnect
only works reliably when it is called after bothonServiceStateChanged
andonAppStatusChanged
have fired with parameters that are non-null
andtrue
, respectively. This suggests the following fix for the non-deterministic behavior:requestConnect
is idempotent to prevent any (theoretical) races.requestConnect
call on bothonServiceStateChanged
andonAppStatusChanged
having fired positively by having each listener check whether the other has already fired and only then callingrequestConnect
.requestConnect
can safely be called synchronously as before.Please let me know if I should have missed anything or introduced a bug elsewhere.