Draft Android implementation of the new platform DNS resolver [chromium/src : main]

0 views
Skip to first unread message

Vladyslav Kasprov (Gerrit)

unread,
Oct 8, 2025, 10:38:01 AM (4 days ago) Oct 8
to Mohannad Farrag, Etienne Dechamps, Stefano Duo, Chromium LUCI CQ, AyeAye, net-r...@chromium.org
Attention needed from Etienne Dechamps and Stefano Duo

Vladyslav Kasprov added 9 comments

Commit Message
Line 7, Patchset 32:Draft Android implementation of the new platform DNS resolver with HTTPS DNS records support. Use android_res_nquery API to implement the resolution.
Stefano Duo . resolved

For Chromium's commit messages, usually first line is a brief summary of up to 50-80 chars, see [this](https://chromium.googlesource.com/chromium/src/+/main/docs/contributing.md#uploading-a-change-for-review).

Then it's a blank line, followed by a more in-depth explanation.

In this case it would be useful in the in-depth explanation to call out that the parsing code for android_res_nresult is throwaway code that will later be substituted with the pre-existing async DNS resolver parsing logic.

Vladyslav Kasprov

Updated the commit message to have a brief summary followed by a blank line and in-depth explanation of in-scope/out of scope things for this CL.

Line 7, Patchset 32:Draft Android implementation of the new platform DNS resolver with HTTPS DNS records support. Use android_res_nquery API to implement the resolution.
Etienne Dechamps . resolved

This commit first line is too long. More generally, see https://cbea.ms/git-commit/

Vladyslav Kasprov

Updated the commit message to have a brief summary followed by a blank line and in-depth explanation.

File net/dns/host_resolver_platform_system_task.h
Line 36, Patchset 31:class NET_EXPORT HostResolverPlatformSystemTask
Stefano Duo . resolved

Can you add a brief comment above stating what this represents? I'm thinking something along the lines of:

```suggestion
// Implements `HostResolverSource::SYSTEM`, similarly to `HostResolverSystemTask`.
// Resolves hostnames querying the system/OS via platform specific APIs, instead of
// getaddrinfo.
class NET_EXPORT HostResolverPlatformSystemTask
```

Vladyslav Kasprov

Updated the comment explaining the purpose of this class.

Does it look good now?

Vladyslav Kasprov

Updated the comment to:

```
Implements DNS resolution using platform specific APIs.

Implements `HostResolverSource::SYSTEM`, similarly to
`HostResolverSystemTask`. However, instead of getaddrinfo, resolves hostnames
using different platform-specific APIs that query the system/OS.

This class is designed to be used only for a single, one-shot hostname
resolution. This class is not thread-safe.

Simply call Start() to start the resolution. The callback will be called on
the thread that called Start() with the results of the resolution.
```

Resolving this thread for now. Let me know if there are more comments.

Line 55, Patchset 28: // synchronously and can own `this`.
Etienne Dechamps . resolved

This wording is a bit confusing. Did you mean "can destroy `this`"?

Vladyslav Kasprov

Updated the comment to:
```
Starts the resolution task. This can only be called once per
HostResolverPlatformSystemTask. `result_callback` will be invoked
asynchronously and can destroy `this`.
```

File net/dns/host_resolver_platform_system_task.cc
Line 63, Patchset 28:std::vector<std::string> extractIpAddressAnswers(uint8_t* buf,
size_t bufLen,
Etienne Dechamps . unresolved

Every time you have something in the form of "pointer to an array and size", you'd be better off using `std::span` to represent it. https://abseil.io/tips/93

Vladyslav Kasprov

Both `std::span` and `absl::Span` are banned in Chromium, in favor of `base::span`. Using `base::span` changes the call site from:
```
ExtractIpAddressAnswers(answer_buf, answer_len, AF_INET);
```
to:
```
ExtractIpAddressAnswers(UNSAFE_BUFFERS(base::span<uint8_t>(answer_buf, static_cast<size_t>(answer_len))), AF_INET);
```

Do you still think we should make this change?

Line 67, Patchset 28: if (ns_initparse((const uint8_t*)buf, bufLen, &handle) < 0) {
Etienne Dechamps . resolved

Nit: it's a bit more robust to write `!= 0` - anything other than zero (even positive numbers) is unexpected, and should be treated as an error. According to that function code it should never return anything greater than zero.

Vladyslav Kasprov

Yes, `0` return value of that function stands for `success`, so anything else is a failure. Changed to `!= 0`

Line 71, Patchset 28: ns_rr rr;
Etienne Dechamps . resolved

Move this declaration further down, closer to where it's used. https://google.github.io/styleguide/cppguide.html#Local_Variables

Vladyslav Kasprov

Moved inside the for-loop

Line 73, Patchset 28: for (int i = 0; i < ancount; i++) {
Etienne Dechamps . resolved

++i

https://google.github.io/styleguide/cppguide.html#Preincrement_and_Predecrement

Vladyslav Kasprov

Changed to `++i`

Line 119, Patchset 31: DCHECK(dns_names_util::IsValidDnsName(hostname_))
Etienne Dechamps . unresolved

Use `CHECK`, not `DCHECK`, unless you can show this is too expensive to run in production. https://chromium.googlesource.com/chromium/src/+/HEAD/styleguide/c++/c++.md#check_dcheck_and-notreached

Do not use existing code as precedent for this. Chromium has historically been infamously bad at using DCHECKs correctly.

Same below, many times.

Vladyslav Kasprov

Changed to `CHECK` and updated documentation. Now if the hostname is invalid, the constuctor will crash. Also, now if `Start` is called multiple times, it will crash on the second call. Left `DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_)` as is, since I'm not sure if it should be changed or not.

Open in Gerrit

Related details

Attention is currently required from:
  • Etienne Dechamps
  • Stefano Duo
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Id1afd33557527bfd546445ededbc25b484ee44d6
Gerrit-Change-Number: 6886009
Gerrit-PatchSet: 51
Gerrit-Owner: Vladyslav Kasprov <vkas...@google.com>
Gerrit-Reviewer: Etienne Dechamps <edec...@google.com>
Gerrit-Reviewer: Stefano Duo <stefa...@google.com>
Gerrit-Reviewer: Vladyslav Kasprov <vkas...@google.com>
Gerrit-CC: Mohannad Farrag <aym...@google.com>
Gerrit-Attention: Stefano Duo <stefa...@google.com>
Gerrit-Attention: Etienne Dechamps <edec...@google.com>
Gerrit-Comment-Date: Wed, 08 Oct 2025 14:37:16 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Vladyslav Kasprov <vkas...@google.com>
Comment-In-Reply-To: Stefano Duo <stefa...@google.com>
Comment-In-Reply-To: Etienne Dechamps <edec...@google.com>
satisfied_requirement
unsatisfied_requirement
open
diffy

Vladyslav Kasprov (Gerrit)

unread,
Oct 9, 2025, 8:33:44 AM (3 days ago) Oct 9
to Mohannad Farrag, Etienne Dechamps, Stefano Duo, Chromium LUCI CQ, AyeAye, net-r...@chromium.org
Attention needed from Etienne Dechamps and Stefano Duo

Vladyslav Kasprov added 5 comments

File net/dns/host_resolver_platform_system_task.h
Line 40, Patchset 31: std::string hostname,
Stefano Duo . resolved

Can you document that this will crash if `hostname` is not valid (similarly to how you would document that a function throws IllegalArgumentException in Java for invalid arguments).

Vladyslav Kasprov

Added the following comment to the constructor:
```
`hostname` should be a valid domain name, and should be checked early
before calling this constructor. Will crash if `hostname` is invalid.
```

File net/dns/host_resolver_platform_system_task.cc
Line 63, Patchset 28:std::vector<std::string> extractIpAddressAnswers(uint8_t* buf,
size_t bufLen,
Etienne Dechamps . resolved

Every time you have something in the form of "pointer to an array and size", you'd be better off using `std::span` to represent it. https://abseil.io/tips/93

Vladyslav Kasprov

Both `std::span` and `absl::Span` are banned in Chromium, in favor of `base::span`. Using `base::span` changes the call site from:
```
ExtractIpAddressAnswers(answer_buf, answer_len, AF_INET);
```
to:
```
ExtractIpAddressAnswers(UNSAFE_BUFFERS(base::span<uint8_t>(answer_buf, static_cast<size_t>(answer_len))), AF_INET);
```

Do you still think we should make this change?

Vladyslav Kasprov

Resolving for now. Let me know if we should still make this change.

Line 119, Patchset 31: DCHECK(dns_names_util::IsValidDnsName(hostname_))
Etienne Dechamps . resolved

Use `CHECK`, not `DCHECK`, unless you can show this is too expensive to run in production. https://chromium.googlesource.com/chromium/src/+/HEAD/styleguide/c++/c++.md#check_dcheck_and-notreached

Do not use existing code as precedent for this. Chromium has historically been infamously bad at using DCHECKs correctly.

Same below, many times.

Vladyslav Kasprov

Changed to `CHECK` and updated documentation. Now if the hostname is invalid, the constuctor will crash. Also, now if `Start` is called multiple times, it will crash on the second call. Left `DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_)` as is, since I'm not sure if it should be changed or not.

Vladyslav Kasprov

Resolving for now. Let me know if `DCHECK_CALLED_ON_VALID_SEQUENCE` should be addressed as well.

File net/dns/host_resolver_platform_system_task_unittest.cc
Line 19, Patchset 28: std::unique_ptr<HostResolverPlatformSystemTask> task_;
Etienne Dechamps . resolved

`unique_ptr` is overkill for this purpose. Use `std::optional`. https://abseil.io/tips/123 https://abseil.io/tips/187

After you move this to a local variable (see other comment), you can go even further and make it a bare object.

Vladyslav Kasprov

Moved `task` to a local variable and made it a bare object

Line 19, Patchset 28: std::unique_ptr<HostResolverPlatformSystemTask> task_;
Etienne Dechamps . resolved

Avoid putting stuff in fixtures if you can. Here you could just make this a local variable inside the test. (Then you could just get rid of the fixture altogether, although I don't think you can as presumably you still need `TestWithTaskEnvironment`.)

More generally, don't use class member variables for things that could be local variables instead.

https://abseil.io/tips/122

Vladyslav Kasprov

Moved `task_` into a local variable.
Replaced `TestWithTaskEnvironment` with a regular `::testing::Test`.

Open in Gerrit

Related details

Attention is currently required from:
  • Etienne Dechamps
  • Stefano Duo
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Id1afd33557527bfd546445ededbc25b484ee44d6
Gerrit-Change-Number: 6886009
Gerrit-PatchSet: 53
Gerrit-Owner: Vladyslav Kasprov <vkas...@google.com>
Gerrit-Reviewer: Etienne Dechamps <edec...@google.com>
Gerrit-Reviewer: Stefano Duo <stefa...@google.com>
Gerrit-Reviewer: Vladyslav Kasprov <vkas...@google.com>
Gerrit-CC: Mohannad Farrag <aym...@google.com>
Gerrit-Attention: Stefano Duo <stefa...@google.com>
Gerrit-Attention: Etienne Dechamps <edec...@google.com>
Gerrit-Comment-Date: Thu, 09 Oct 2025 12:32:57 +0000
satisfied_requirement
unsatisfied_requirement
open
diffy

Vladyslav Kasprov (Gerrit)

unread,
Oct 9, 2025, 11:00:02 AM (3 days ago) Oct 9
to Mohannad Farrag, Etienne Dechamps, Stefano Duo, Chromium LUCI CQ, AyeAye, net-r...@chromium.org
Attention needed from Etienne Dechamps and Stefano Duo

Vladyslav Kasprov added 6 comments

File net/dns/host_resolver_platform_system_task.cc
Line 265, Patchset 32: TRACE_EVENT0(NetTracingCategory(),
"HostResolverPlatformSystemTask::OnLookupComplete");
Etienne Dechamps . resolved

If you're going to add trace events (and you should), then you may as well sprinkle them everywhere, e.g. in Start().

Vladyslav Kasprov

Removed tracing events for now

Line 273, Patchset 32: if (*net_error != OK && NetworkChangeNotifier::IsOffline()) {
*net_error = ERR_INTERNET_DISCONNECTED;
Etienne Dechamps . resolved

Just making sure: is it really this layer's responsibility to check for this? This seems like something that could/should be checked at a higher layer, with this layer merely returning the raw error from the OS.

Vladyslav Kasprov

We want to keep this, because [the existing system resolver does this too](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/net/dns/host_resolver_system_task.cc#449). We want to have the new resolver to be a drop-in replacement of the old one, and keep the same API. This `net_error` code is part of the API because it is passed to the caller in the result callback.

Line 278, Patchset 28: net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_SYSTEM_TASK, [&] {
Stefano Duo . resolved

This should rely on a new NetLogEventType::HOST_RESOLVER_PLATFORM_SYSTEM_TASK.

Event types are defined [here](https://crsrc.org/c/net/log/net_log_event_type_list.h;l=195-211;drc=ae249e81ef263546d4b6d1cd5fbb5101e6f94374).

Vladyslav Kasprov

Removed net logs.

Line 282, Patchset 28: NetLogEventType::HOST_RESOLVER_MANAGER_ATTEMPT_FINISHED,
Stefano Duo . resolved

[HOST_RESOLVER_MANAGER_ATTEMPT_{STARTED, FINISHED}'s documentation](https://crsrc.org/c/net/log/net_log_event_type_list.h;l=138-161;drc=ae249e81ef263546d4b6d1cd5fbb5101e6f94374) seems out of date (HostResolverManager::ProcTask does not exist anymore?).

Having said that, it seems that it's used only by [HostResolverSystemTask::StartLookupAttempt](https://source.chromium.org/search?q=HOST_RESOLVER_MANAGER_ATTEMPT_STARTED&sq=&ss=chromium%2Fchromium%2Fsrc).

Vladyslav Kasprov

Removed net logs.

Line 279, Patchset 32: return NetLogFailedParams(0, *net_error, *os_error);
});
net_log_.AddEvent(
NetLogEventType::HOST_RESOLVER_MANAGER_ATTEMPT_FINISHED,
[&] { return NetLogFailedParams(1, *net_error, *os_error); });
} else {
net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_SYSTEM_TASK,
[&] { return results->NetLogParams(); });
net_log_.AddEventWithIntParams(
NetLogEventType::HOST_RESOLVER_MANAGER_ATTEMPT_FINISHED,
"attempt_number", 1);
Etienne Dechamps . resolved

I'm a bit confused as to how we are populating "attempt_number" here. It looks like we are only attempting once? Then why do we even populate this field in the netlog? Also, Why do we set it to 0 in `HOST_RESOLVER_SYSTEM_TASK` but 0 in `HOST_RESOLVER_MANAGER_ATTEMPT_FINISHED`?

Vladyslav Kasprov

Removed net logs altogether. We won't be adding them for now.

File net/dns/host_resolver_platform_system_task_unittest.cc
Line 19, Patchset 28: std::unique_ptr<HostResolverPlatformSystemTask> task_;
Etienne Dechamps . resolved

Avoid putting stuff in fixtures if you can. Here you could just make this a local variable inside the test. (Then you could just get rid of the fixture altogether, although I don't think you can as presumably you still need `TestWithTaskEnvironment`.)

More generally, don't use class member variables for things that could be local variables instead.

https://abseil.io/tips/122

Vladyslav Kasprov

Moved `task_` into a local variable.
Replaced `TestWithTaskEnvironment` with a regular `::testing::Test`.

Vladyslav Kasprov

Reverted `TestWithTaskEnvironment` change because `RunLoop` requires it.
`task_` is still a local variable.

Open in Gerrit

Related details

Attention is currently required from:
  • Etienne Dechamps
  • Stefano Duo
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Id1afd33557527bfd546445ededbc25b484ee44d6
Gerrit-Change-Number: 6886009
Gerrit-PatchSet: 54
Gerrit-Owner: Vladyslav Kasprov <vkas...@google.com>
Gerrit-Reviewer: Etienne Dechamps <edec...@google.com>
Gerrit-Reviewer: Stefano Duo <stefa...@google.com>
Gerrit-Reviewer: Vladyslav Kasprov <vkas...@google.com>
Gerrit-CC: Mohannad Farrag <aym...@google.com>
Gerrit-Attention: Stefano Duo <stefa...@google.com>
Gerrit-Attention: Etienne Dechamps <edec...@google.com>
Gerrit-Comment-Date: Thu, 09 Oct 2025 14:59:17 +0000
satisfied_requirement
unsatisfied_requirement
open
diffy

Vladyslav Kasprov (Gerrit)

unread,
Oct 9, 2025, 11:52:10 AM (3 days ago) Oct 9
to Mohannad Farrag, Etienne Dechamps, Stefano Duo, Chromium LUCI CQ, AyeAye, net-r...@chromium.org
Attention needed from Stefano Duo and Vladyslav Kasprov

Vladyslav Kasprov added 10 comments

File net/dns/host_resolver_platform_system_task.cc
Line 61, Patchset 28:constexpr int MAXPACKET = 8 * 1024;
Etienne Dechamps . resolved

Nit: somewhat of a (controversial) personal opinion, but I would not usually define constants that are only used once - all that does is inflict a back-and-forth across the file on the unfortunate reader for no real benefit.

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 61, Patchset 28:constexpr int MAXPACKET = 8 * 1024;
Etienne Dechamps . resolved

Can you document what this is, and how the value was chosen?

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 75, Patchset 28: continue;
Etienne Dechamps . resolved

Maybe `VLOG(1)` in this case, for ease of troubleshooting?

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 78, Patchset 28: char buffer[INET6_ADDRSTRLEN];
Etienne Dechamps . resolved

How do you know the address is `AF_INET6`?

If the address is actually `AF_INET` then this is the wrong size, and will produce the wrong result (if it doesn't fail outright in `inet_ntop`).

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 79, Patchset 28: if (inet_ntop(ipType, (const char*)rdata, buffer, sizeof(buffer))) {
Etienne Dechamps . resolved

Nit: it would be more robust to write `== buffer`, which is what the function is expected to return.

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 80, Patchset 28: answers.push_back(buffer);
Etienne Dechamps . resolved

This will incur an unnecessary copy into an `std::string`.

A more efficient way would be:

```
std::string buffer(INET6_ADDRSTRLEN);
inet_ntop(..., buffer.data(), buffer.size());
answers.push_back(std::move(buffer));
```

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 202, Patchset 32: // This line is important to keep to avoid internal MessagePumpEpoll crash.
Etienne Dechamps . resolved

Can you add more detail here? Why does it crash otherwise? What is the API contract here?

Vladyslav Kasprov

This will be investigated as part of a separate bug (https://crbug.com/450545129)

Line 233, Patchset 32: const auto ip_address = IPAddress::FromIPLiteral(answer);
Etienne Dechamps . resolved

This is round-tripping the IP address from binary (bytes) to string and then back to bytes? Wouldn't it be more straightforward and efficient to just create the IPAddress directly from the raw bytes? It would also eliminate the possibility that this could fail (i.e. your if below)

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 234, Patchset 32: if (ip_address) {
Etienne Dechamps . resolved

Maybe `VLOG(1)` in this is false, for ease of troubleshooting?

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Line 235, Patchset 32: addr_list->push_back(IPEndPoint(*ip_address, 0));
Etienne Dechamps . resolved

Returning a zero port seems... odd? Can you add a comment to explain why this is fine?

Vladyslav Kasprov

This code is part of the throwaway parsing logic, which is going to be replaced with the proper parsing logic in the future CLs. See more details in [crbug.com/449966580](https://crbug.com/449966580) and [go/https-rr-android-design-doc](go/https-rr-android-design-doc#heading=h.at7a3712jww9).

Open in Gerrit

Related details

Attention is currently required from:
  • Stefano Duo
  • Vladyslav Kasprov
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Id1afd33557527bfd546445ededbc25b484ee44d6
    Gerrit-Change-Number: 6886009
    Gerrit-PatchSet: 55
    Gerrit-Owner: Vladyslav Kasprov <vkas...@google.com>
    Gerrit-Reviewer: Etienne Dechamps <edec...@google.com>
    Gerrit-Reviewer: Stefano Duo <stefa...@google.com>
    Gerrit-Reviewer: Vladyslav Kasprov <vkas...@google.com>
    Gerrit-CC: Mohannad Farrag <aym...@google.com>
    Gerrit-Attention: Vladyslav Kasprov <vkas...@google.com>
    Gerrit-Attention: Stefano Duo <stefa...@google.com>
    Gerrit-Comment-Date: Thu, 09 Oct 2025 15:51:25 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Etienne Dechamps <edec...@google.com>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Etienne Dechamps (Gerrit)

    unread,
    Oct 9, 2025, 12:43:40 PM (3 days ago) Oct 9
    to Vladyslav Kasprov, Mohannad Farrag, Etienne Dechamps, Stefano Duo, Chromium LUCI CQ, AyeAye, net-r...@chromium.org
    Attention needed from Stefano Duo and Vladyslav Kasprov

    Etienne Dechamps added 6 comments

    File net/dns/host_resolver_platform_system_task.h
    Line 19, Patchset 56 (Latest):// Implements DNS resolution using platform specific APIs.
    //

    // Implements `HostResolverSource::SYSTEM`, similarly to
    // `HostResolverSystemTask`. However, instead of getaddrinfo, resolves hostnames
    // using different platform-specific APIs that query the system/OS.
    //
    // This class is designed to be used only for a single, one-shot hostname
    // resolution. This class is not thread-safe.
    //
    // Simply call Start() to start the resolution. The callback will be called on
    // the thread that called Start() with the results of the resolution.
    class NET_EXPORT HostResolverPlatformSystemTask final
    Etienne Dechamps . unresolved

    I think this is too generic. It should have "Android" in the file and class name (I would even go as far as to call it `AndroidResNquerySystemTask`). There is no way this class can be reused across platforms - starting with the Android-specific `__INTRODUCED_IN` attributes, and the whole fd watching stuff.

    That is not to say we shouldn't have a platform-agnostic abstraction, but this is clearly not that, and can be introduced later (e.g. as an abstract class).

    Line 51, Patchset 31: ~HostResolverPlatformSystemTask() override;
    Stefano Duo . unresolved

    You can drop the override here since this class is not being extended (I also don't think we plan to).

    Etienne Dechamps

    The override is because the class is implementing FdWatcher. But even then, it is true that override is typically not useful on destructors anyway.

    Vladyslav Kasprov

    Removing the `override` results in a [modernize-use-override](https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-override.html) warning from `clang-tidy`:

    ```
    Annotate this function with 'override' or (rarely) 'final'
    ```

    I marked it as `final` instead.


    Does it look good now?

    Vladyslav Kasprov

    Resolving this comment for now.
    Let me know if this issue wasn't fully addressed, and more changes are needed.

    Etienne Dechamps

    If clang-tidy complains, just leave it as `override`. `final` is technically fine here, but is weird and unusual.

    File net/dns/host_resolver_platform_system_task.cc
    Line 104, Patchset 56 (Latest): int errno_copy = errno;
    Etienne Dechamps . unresolved

    Can you point me to the doc on this `WatchFileDescriptor` that states that errors are surfaced through errno?

    If there is no such doc, I wouldn't assume they are, and instead treat it as an unknown error.

    Line 119, Patchset 56 (Latest): // TODO: This should never happen. Add a trace event to detect if it does.
    Etienne Dechamps . unresolved

    I think you should downright CHECK-fail on this. Given you annotated your public API with `__INTRODUCED_IN(29)`, it is the responsibility of the user of the class to ensure they do not use this class on API < 29. Besides, we shouldn't even be able to get here if API < 29.

    Line 273, Patchset 32: if (*net_error != OK && NetworkChangeNotifier::IsOffline()) {
    *net_error = ERR_INTERNET_DISCONNECTED;
    Etienne Dechamps . unresolved

    Just making sure: is it really this layer's responsibility to check for this? This seems like something that could/should be checked at a higher layer, with this layer merely returning the raw error from the OS.

    Vladyslav Kasprov

    We want to keep this, because [the existing system resolver does this too](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/net/dns/host_resolver_system_task.cc#449). We want to have the new resolver to be a drop-in replacement of the old one, and keep the same API. This `net_error` code is part of the API because it is passed to the caller in the result callback.

    Etienne Dechamps

    Can you explain this in a code comment?

    File net/dns/host_resolver_platform_system_task_unittest.cc
    Line 55, Patchset 56 (Latest): FAIL() << "This test is failing because it has to be run on Android 29+.";
    Etienne Dechamps . unresolved

    I don't think this will pass CQ, as it will try your test on older versions of Android (in addition to recent ones).

    What you want is GTEST_SKIP() instead. https://google.github.io/googletest/reference/testing.html#GTEST_SKIP unless there is a better way to restrict a gUnit test to specific Android API versions that I am not aware of.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Stefano Duo
    • Vladyslav Kasprov
    Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement is not satisfiedCode-Owners
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement is not satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Id1afd33557527bfd546445ededbc25b484ee44d6
      Gerrit-Change-Number: 6886009
      Gerrit-PatchSet: 56
      Gerrit-Owner: Vladyslav Kasprov <vkas...@google.com>
      Gerrit-Reviewer: Etienne Dechamps <edec...@google.com>
      Gerrit-Reviewer: Stefano Duo <stefa...@google.com>
      Gerrit-Reviewer: Vladyslav Kasprov <vkas...@google.com>
      Gerrit-CC: Mohannad Farrag <aym...@google.com>
      Gerrit-Attention: Vladyslav Kasprov <vkas...@google.com>
      Gerrit-Attention: Stefano Duo <stefa...@google.com>
      Gerrit-Comment-Date: Thu, 09 Oct 2025 16:42:52 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Vladyslav Kasprov (Gerrit)

      unread,
      Oct 10, 2025, 9:24:10 AM (2 days ago) Oct 10
      to Mohannad Farrag, Etienne Dechamps, Stefano Duo, Chromium LUCI CQ, AyeAye, net-r...@chromium.org
      Attention needed from Etienne Dechamps and Stefano Duo

      Vladyslav Kasprov added 6 comments

      File net/dns/host_resolver_platform_system_task.h
      Line 19, Patchset 56:// Implements DNS resolution using platform specific APIs.

      //
      // Implements `HostResolverSource::SYSTEM`, similarly to
      // `HostResolverSystemTask`. However, instead of getaddrinfo, resolves hostnames
      // using different platform-specific APIs that query the system/OS.
      //
      // This class is designed to be used only for a single, one-shot hostname
      // resolution. This class is not thread-safe.
      //
      // Simply call Start() to start the resolution. The callback will be called on
      // the thread that called Start() with the results of the resolution.
      class NET_EXPORT HostResolverPlatformSystemTask final
      Etienne Dechamps . resolved

      I think this is too generic. It should have "Android" in the file and class name (I would even go as far as to call it `AndroidResNquerySystemTask`). There is no way this class can be reused across platforms - starting with the Android-specific `__INTRODUCED_IN` attributes, and the whole fd watching stuff.

      That is not to say we shouldn't have a platform-agnostic abstraction, but this is clearly not that, and can be introduced later (e.g. as an abstract class).

      Vladyslav Kasprov

      Renamed to `PlatformDnsQueryExecutorAndroid`.

      [go/https-rr-android-design-doc](go/https-rr-android-design-doc) proposes introducing `PlatformDnsQueryExecutor` base class responsible for resolving hostnames. It's implementations would be platform-specific.

      The class introducted in this CL is basically an Android implementation of the proposed `PlatformDnsQueryExecutor`. Hence, I named it `PlatformDnsQueryExecutorAndroid`. Adding a platform suffix seems to be standard practice in Chromium. I took inspiration from an existing `DnsConfigService` class and its implementations.

      Line 51, Patchset 31: ~HostResolverPlatformSystemTask() override;
      Stefano Duo . resolved

      You can drop the override here since this class is not being extended (I also don't think we plan to).

      Etienne Dechamps

      The override is because the class is implementing FdWatcher. But even then, it is true that override is typically not useful on destructors anyway.

      Vladyslav Kasprov

      Removing the `override` results in a [modernize-use-override](https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-override.html) warning from `clang-tidy`:

      ```
      Annotate this function with 'override' or (rarely) 'final'
      ```

      I marked it as `final` instead.
      Does it look good now?

      Vladyslav Kasprov

      Resolving this comment for now.
      Let me know if this issue wasn't fully addressed, and more changes are needed.

      Etienne Dechamps

      If clang-tidy complains, just leave it as `override`. `final` is technically fine here, but is weird and unusual.

      Vladyslav Kasprov

      Reverted to `override`.

      File net/dns/host_resolver_platform_system_task.cc
      Line 104, Patchset 56: int errno_copy = errno;
      Etienne Dechamps . resolved

      Can you point me to the doc on this `WatchFileDescriptor` that states that errors are surfaced through errno?

      If there is no such doc, I wouldn't assume they are, and instead treat it as an unknown error.

      Vladyslav Kasprov

      I couldn't find any docs for `WatchFileDescriptor` itself. However.

      Depending on the platform, `WatchFileDescriptor` has multiple implementations. On Android, it [resolves](https://chromium.googlesource.com/chromium/src/+/main/base/message_loop/message_pump_for_io.h#23) to [MessagePumpEpoll::WatchFileDescriptor](https://chromium.googlesource.com/chromium/src/+/main/base/message_loop/message_pump_epoll.h#128).

      Internally, `MessagePumpEpoll::WatchFileDescriptor ` uses [epoll_ctl](https://litux.nl/man/htmlman2/epoll_ctl.2.html), which **is** documented to set `errno` appropriately on error.

      Line 119, Patchset 56: // TODO: This should never happen. Add a trace event to detect if it does.
      Etienne Dechamps . resolved

      I think you should downright CHECK-fail on this. Given you annotated your public API with `__INTRODUCED_IN(29)`, it is the responsibility of the user of the class to ensure they do not use this class on API < 29. Besides, we shouldn't even be able to get here if API < 29.

      Vladyslav Kasprov
      Changed this `if-else` to:
      ```
      if (__builtin_available(android 29, *)) {
      ReadPlatformResponseAndroid29(fd);
      } else {
      // The only time this class is expected to receive this callback is when
      // reading a file descriptor returned by android_res_nquery() API, which is
      // available only on Android 29+. Change this code if this class starts to
      // read file descriptors for other purposes. Until then, this is a safety
      // check to crash early if this code path is reached.
      CHECK(false);
      }
      ```
      Line 273, Patchset 32: if (*net_error != OK && NetworkChangeNotifier::IsOffline()) {
      *net_error = ERR_INTERNET_DISCONNECTED;
      Etienne Dechamps . resolved

      Just making sure: is it really this layer's responsibility to check for this? This seems like something that could/should be checked at a higher layer, with this layer merely returning the raw error from the OS.

      Vladyslav Kasprov

      We want to keep this, because [the existing system resolver does this too](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/net/dns/host_resolver_system_task.cc#449). We want to have the new resolver to be a drop-in replacement of the old one, and keep the same API. This `net_error` code is part of the API because it is passed to the caller in the result callback.

      Etienne Dechamps

      Can you explain this in a code comment?

      Vladyslav Kasprov

      Added the following comment:
      ```
      // This logic is copied from `HostResolverSystemTask`. This class is designed
      // as drop-in replacement for `HostResolverSystemTask`, and hence had to mimic
      // its API. `net_error` is part of the API because it's returned to the user
      // in the `result_callback_`.
      ```

      File net/dns/host_resolver_platform_system_task_unittest.cc
      Line 55, Patchset 56: FAIL() << "This test is failing because it has to be run on Android 29+.";
      Etienne Dechamps . resolved

      I don't think this will pass CQ, as it will try your test on older versions of Android (in addition to recent ones).

      What you want is GTEST_SKIP() instead. https://google.github.io/googletest/reference/testing.html#GTEST_SKIP unless there is a better way to restrict a gUnit test to specific Android API versions that I am not aware of.

      Vladyslav Kasprov

      Changed this `FAIL()` to:
      ```
      GTEST_SKIP_("The class that's being tested is available only on Android 29+");
      ```

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Etienne Dechamps
      • Stefano Duo
      Submit Requirements:
        • requirement satisfiedCode-Coverage
        • requirement is not satisfiedCode-Owners
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: chromium/src
        Gerrit-Branch: main
        Gerrit-Change-Id: Id1afd33557527bfd546445ededbc25b484ee44d6
        Gerrit-Change-Number: 6886009
        Gerrit-PatchSet: 58
        Gerrit-Owner: Vladyslav Kasprov <vkas...@google.com>
        Gerrit-Reviewer: Etienne Dechamps <edec...@google.com>
        Gerrit-Reviewer: Stefano Duo <stefa...@google.com>
        Gerrit-Reviewer: Vladyslav Kasprov <vkas...@google.com>
        Gerrit-CC: Mohannad Farrag <aym...@google.com>
        Gerrit-Attention: Stefano Duo <stefa...@google.com>
        Gerrit-Attention: Etienne Dechamps <edec...@google.com>
        Gerrit-Comment-Date: Fri, 10 Oct 2025 13:23:25 +0000
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy

        Etienne Dechamps (Gerrit)

        unread,
        Oct 10, 2025, 1:06:40 PM (2 days ago) Oct 10
        to Vladyslav Kasprov, Etienne Dechamps, Mohannad Farrag, Stefano Duo, Chromium LUCI CQ, AyeAye, net-r...@chromium.org
        Attention needed from Stefano Duo and Vladyslav Kasprov

        Etienne Dechamps voted and added 2 comments

        Votes added by Etienne Dechamps

        Code-Review+1

        2 comments

        File net/dns/host_resolver_platform_system_task.cc
        Line 104, Patchset 56: int errno_copy = errno;
        Etienne Dechamps . unresolved

        Can you point me to the doc on this `WatchFileDescriptor` that states that errors are surfaced through errno?

        If there is no such doc, I wouldn't assume they are, and instead treat it as an unknown error.

        Vladyslav Kasprov

        I couldn't find any docs for `WatchFileDescriptor` itself. However.

        Depending on the platform, `WatchFileDescriptor` has multiple implementations. On Android, it [resolves](https://chromium.googlesource.com/chromium/src/+/main/base/message_loop/message_pump_for_io.h#23) to [MessagePumpEpoll::WatchFileDescriptor](https://chromium.googlesource.com/chromium/src/+/main/base/message_loop/message_pump_epoll.h#128).

        Internally, `MessagePumpEpoll::WatchFileDescriptor ` uses [epoll_ctl](https://litux.nl/man/htmlman2/epoll_ctl.2.html), which **is** documented to set `errno` appropriately on error.

        Etienne Dechamps

        The problem with this is:

        1. There is no guarantee the implementation will be careful to preserve errno for callers. It is very easy to trample errno - for example, just calling `LOG(...) << ...` will trample errno (because it triggers I/O). This makes this mechanism very brittle and the resulting error code may be subtly wrong in ways that may be hard to notice.
        2. Even if the implementation preserves errno now, there is no guarantee that it will continue to do so, especially since that's not documented. We should not rely on undocumented behavior.

        File net/dns/platform_dns_query_executor_android.cc
        Line 147, Patchset 59 (Latest): std::vector<std::string> answers =
        Etienne Dechamps . unresolved

        This variable is unnecessary, and could be inlined. https://abseil.io/tips/161

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Stefano Duo
        • Vladyslav Kasprov
        Submit Requirements:
          • requirement satisfiedCode-Coverage
          • requirement is not satisfiedCode-Owners
          • requirement is not satisfiedCode-Review
          • requirement is not satisfiedNo-Unresolved-Comments
          • requirement satisfiedReview-Enforcement
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: chromium/src
          Gerrit-Branch: main
          Gerrit-Change-Id: Id1afd33557527bfd546445ededbc25b484ee44d6
          Gerrit-Change-Number: 6886009
          Gerrit-PatchSet: 59
          Gerrit-Owner: Vladyslav Kasprov <vkas...@google.com>
          Gerrit-Reviewer: Etienne Dechamps <edec...@google.com>
          Gerrit-Reviewer: Stefano Duo <stefa...@google.com>
          Gerrit-Reviewer: Vladyslav Kasprov <vkas...@google.com>
          Gerrit-CC: Mohannad Farrag <aym...@google.com>
          Gerrit-Attention: Vladyslav Kasprov <vkas...@google.com>
          Gerrit-Attention: Stefano Duo <stefa...@google.com>
          Gerrit-Comment-Date: Fri, 10 Oct 2025 17:05:33 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: Yes
          Comment-In-Reply-To: Vladyslav Kasprov <vkas...@google.com>
          Comment-In-Reply-To: Etienne Dechamps <edec...@google.com>
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy
          Reply all
          Reply to author
          Forward
          0 new messages