-
-
Notifications
You must be signed in to change notification settings - Fork 742
Add WearDns for handling DNS resolution on Wear devices #5170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This commit introduces a new `WearDns` class to handle DNS resolution on Wear OS devices. It attempts to use the system DNS and falls back to mobile DNS if there's an issue. The implementation includes: - `dns_via_mobile`: Constant for the mobile DNS capability.
common/src/main/kotlin/io/homeassistant/companion/android/common/data/DataModule.kt
Fixed
Show fixed
Hide fixed
common/src/main/kotlin/io/homeassistant/companion/android/common/data/HomeAssistantApis.kt
Fixed
Show fixed
Hide fixed
wear/src/main/kotlin/io/homeassistant/companion/android/data/WearDataModule.kt
Fixed
Show fixed
Hide fixed
wear/src/main/kotlin/io/homeassistant/companion/android/data/WearDataModule.kt
Fixed
Show fixed
Hide fixed
This commit introduces a new `WearDns` class to handle DNS resolution on Wear OS devices. It attempts to use the system DNS and falls back to mobile DNS if there's an issue. The implementation includes: - `dns_via_mobile`: Constant for the mobile DNS capability.
# Conflicts: # wear/src/main/kotlin/io/homeassistant/companion/android/data/WearDns.kt
wear/src/main/kotlin/io/homeassistant/companion/android/phone/PhoneSettingsListener.kt
Fixed
Show fixed
Hide fixed
wear/src/main/kotlin/io/homeassistant/companion/android/phone/PhoneSettingsListener.kt
Fixed
Show fixed
Hide fixed
wear/src/main/kotlin/io/homeassistant/companion/android/phone/PhoneSettingsListener.kt
Fixed
Show fixed
Hide fixed
Open Questions
|
app/src/full/kotlin/io/homeassistant/companion/android/data/wear/WearDataListener.kt
Outdated
Show resolved
Hide resolved
import okhttp3.Dns | ||
|
||
@AndroidEntryPoint | ||
class WearDataListener : WearableListenerService() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you envision this class to evolve? The name seems quite generic. Could you add a description within the code of the scope of the listener?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, happy for guidance here.
I'll document the current scope (mobile providing helper APIs for networking/data).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case if you envision it to be for general networking/data I would suggest to follow Google documentation
For best performance, limit the number of listeners and use mutually exclusive filters where there are multiple listeners. A common pattern is to use prefix filters to listen to different namespaces within an application.
And introduce a namespace in the intent-filter something like android:pathPrefix="/network"
and update the path to look like /network/dnsLookup
…ar/WearDataListener.kt Co-authored-by: Timothy <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that for now we don't need a user preference for it (but it can be added later if needed). But I think it worse mentioning this behavior inside the https://companion.home-assistant.io/ (github https://github.com/home-assistant/companion.home-assistant).
For the retry I don't know we can go with your proposal and see if people are raising new issues about it.
app/src/full/kotlin/io/homeassistant/companion/android/data/wear/WearDataListener.kt
Show resolved
Hide resolved
common/src/main/kotlin/io/homeassistant/companion/android/common/data/HomeAssistantApis.kt
Outdated
Show resolved
Hide resolved
/** | ||
* Wear specific implementation of Dns that defaults to the System DNS, | ||
* but can fall back to relying on mobile Dns to resolve dns issues. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Be a bit more specific saying that it uses the messageAPI to query /dnsLookup with the hostname. Add a mention about the caching mechanism in place.
wear/src/main/kotlin/io/homeassistant/companion/android/data/WearDns.kt
Outdated
Show resolved
Hide resolved
|
||
return addresses | ||
} catch (e2: Exception) { | ||
e2.addSuppressed(e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two error combined (UnknownHostException
) might be a bit hard to read. I think you better with proper logging here.
Add a log in the first catch something like that
Timber.e(e, "DNS resolution using the system DNS failed, fallback onto mobile DNS lookup."
if (path == "/dnsLookup") { | ||
val hostname = String(request, Charsets.UTF_8) | ||
return mainScope.async(Dispatchers.IO) { | ||
Dns.SYSTEM.lookup(hostname).first().address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why only returning the first? If I'm not wrong you could get at two InnetAddress one for ipv4 and one for ipv6. The wear could benefits having the two.
It avoid having some logic here you just forward whatever you received without transformation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. Should I json encode the request and response? Would be more inline with other uses?
This actually reminds me, we should prefer IPv4, as I'm not sure the BT proxied connection supports IPv6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with JSON. Even if we should prefer IPv4 let's not take any decision at this level. The wear should deal with that not the mobile.
import okhttp3.Dns | ||
|
||
@AndroidEntryPoint | ||
class WearDataListener : WearableListenerService() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case if you envision it to be for general networking/data I would suggest to follow Google documentation
For best performance, limit the number of listeners and use mutually exclusive filters where there are multiple listeners. A common pattern is to use prefix filters to listen to different namespaces within an application.
And introduce a namespace in the intent-filter something like android:pathPrefix="/network"
and update the path to look like /network/dnsLookup
sealed interface CacheResult { | ||
val storedAt: Instant | ||
} | ||
|
||
data class NegativeCacheHit(val exception: Exception, override val storedAt: Instant) : CacheResult | ||
data class PositiveCacheHit(val value: List<InetAddress>, override val storedAt: Instant) : CacheResult |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make this private?
if (response.isEmpty()) { | ||
throw UnknownHostException("Mobile helper unable to resolve $hostname") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should do that, the normal behavior of OkHttp is just passing the empty list down the chain. If you received an empty list for the API forward it OkHttp will fail later.
Since we inject this class in the HomeAssistantAPI I rather replicate exactly what the default behavior does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All current implementations of Dns throw on empty.
As you say it ends up the same, butI think throwing here is more correct.
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
…on/data/HomeAssistantApis.kt Co-authored-by: Timothy <[email protected]>
…earDns.kt Co-authored-by: Timothy <[email protected]>
Would you mind adding some Unit test? I've added recently all the necessary tools to add them. |
@TimoPtr testing is hard with the DataLayer. In either instrumentation (need paired devices), or unit test (robolectric with custom shadows?). I'll refactor to have some API we control for the DataLayer parts and test the rest of the structure. I'm assuming unit tests based on this being recently added https://github.com/home-assistant/android/blob/master/common/src/test/kotlin/io/homeassistant/companion/android/common/data/websocket/impl/entities/ConversationResponseTest.kt And put them under wear/src/test/kotlin |
Yes unit test, unit test with robolectric and instrumentation test have been setup recently. For now it only contains very simple tests, I used them to work on the CI that run everything now. Lemme know if you need anything for writing the tests. I can help since it's still WIP. |
Summary
This commit introduces a new
WearDns
class to handle DNS resolution on Wear OS devices. It attempts to use the system DNS and falls back to mobile DNS if there's an issue.The implementation includes:
mobile_network_helper
: Constant for the mobile DNS capability./dnsLookup
: Constant for the mobile DNS request.Any other notes
I'm experimenting to address #1866
If this isn't working, then next option to explore is requiring Wifi. See https://google.github.io/horologist/network-awareness/