Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e17c5f2 authored by paulhu's avatar paulhu
Browse files

[DRUEL05] Implement unsolicited dns health event

Implement unsolicited dns health event that will report to the
listener when get dns lookup result.

Bug: 173485754
Test: atest resolv_integration_test resolv_unit_test\
      resolv_stress_test resolv_stats_test_utils_test
Change-Id: Ib44304b3806838682c6403973e364ff5825f7eb0
parent dcadba54
Loading
Loading
Loading
Loading
+31 −2
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@
#include "stats.pb.h"

using aidl::android::net::metrics::INetdEventListener;
using aidl::android::net::resolv::aidl::DnsHealthEventParcel;
using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
using android::net::NetworkDnsEventReported;

namespace android {
@@ -347,16 +349,43 @@ void reportDnsEvent(int eventType, const android_net_context& netContext, int la
    maybeLogQuery(eventType, netContext, event, query_name, ip_addrs);

    const auto& listeners = ResolverEventReporter::getInstance().getListeners();
    if (listeners.size() == 0) {
    if (listeners.empty()) {
        LOG(ERROR) << __func__
                   << ": DNS event not sent since no INetdEventListener receiver is available.";
        return;
    }
    const int latencyMs = latencyUs / 1000;
    for (const auto& it : listeners) {
        it->onDnsEvent(netContext.dns_netid, eventType, returnCode, latencyMs, query_name, ip_addrs,
                       total_ip_addr_count, netContext.uid);
    }

    const auto& unsolEventListeners = ResolverEventReporter::getInstance().getUnsolEventListeners();

    if (returnCode == NETD_RESOLV_TIMEOUT) {
        const DnsHealthEventParcel dnsHealthEvent = {
                .netId = static_cast<int32_t>(netContext.dns_netid),
                .healthResult = IDnsResolverUnsolicitedEventListener::DNS_HEALTH_RESULT_TIMEOUT,
        };
        for (const auto& it : unsolEventListeners) {
            it->onDnsHealthEvent(dnsHealthEvent);
        }
    } else if (returnCode == NOERROR) {
        DnsHealthEventParcel dnsHealthEvent = {
                .netId = static_cast<int32_t>(netContext.dns_netid),
                .healthResult = IDnsResolverUnsolicitedEventListener::DNS_HEALTH_RESULT_OK,
        };
        for (const auto& query : event.dns_query_events().dns_query_event()) {
            if (query.cache_hit() != CS_FOUND && query.rcode() == NS_R_NO_ERROR) {
                dnsHealthEvent.successRttMicros.push_back(query.latency_micros());
            }
        }

        if (!dnsHealthEvent.successRttMicros.empty()) {
            for (const auto& it : unsolEventListeners) {
                it->onDnsHealthEvent(dnsHealthEvent);
            }
        }
    }
}

bool onlyIPv4Answers(const addrinfo* res) {
+15 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ using aidl::android::net::IDnsResolver;
using aidl::android::net::INetd;
using aidl::android::net::ResolverParamsParcel;
using aidl::android::net::metrics::INetdEventListener;
using aidl::android::net::resolv::aidl::DnsHealthEventParcel;
using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
using aidl::android::net::resolv::aidl::Nat64PrefixEventParcel;
using aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
@@ -292,6 +293,20 @@ class ResolverTest : public ::testing::Test {
            if (dnsEvent.value() == expect) break;
            LOG(INFO) << "Skip unexpected DnsEvent: " << dnsEvent.value();
        } while (true);

        while (returnCode == 0 || returnCode == RCODE_TIMEOUT) {
            // Blocking call until timeout.
            Result<int> result = sUnsolicitedEventListener->popDnsHealthResult();
            ASSERT_TRUE(result.ok()) << "Expected dns health result is " << returnCode;
            if ((returnCode == 0 &&
                 result.value() == IDnsResolverUnsolicitedEventListener::DNS_HEALTH_RESULT_OK) ||
                (returnCode == RCODE_TIMEOUT &&
                 result.value() ==
                         IDnsResolverUnsolicitedEventListener::DNS_HEALTH_RESULT_TIMEOUT)) {
                break;
            }
            LOG(INFO) << "Skip unexpected dns health result:" << result.value();
        }
    }

    enum class StatsCmp { LE, EQ };
+25 −3
Original line number Diff line number Diff line
@@ -23,18 +23,21 @@

namespace android::net::resolv::aidl {

using ::aidl::android::net::resolv::aidl::DnsHealthEventParcel;
using ::aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
using ::aidl::android::net::resolv::aidl::Nat64PrefixEventParcel;
using ::aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
using android::base::Error;
using android::base::Result;
using android::base::ScopedLockAssertion;
using std::chrono::milliseconds;

constexpr milliseconds kEventTimeoutMs{5000};
constexpr milliseconds kRetryIntervalMs{20};

::ndk::ScopedAStatus UnsolicitedEventListener::onDnsHealthEvent(
        const ::aidl::android::net::resolv::aidl::DnsHealthEventParcel&) {
    // default no-op
::ndk::ScopedAStatus UnsolicitedEventListener::onDnsHealthEvent(const DnsHealthEventParcel& event) {
    std::lock_guard lock(mMutex);
    if (event.netId == mNetId) mDnsHealthResultRecords.push(event.healthResult);
    return ::ndk::ScopedAStatus::ok();
}

@@ -105,4 +108,23 @@ bool UnsolicitedEventListener::waitForNat64Prefix(int operation, const milliseco
    return false;
}

Result<int> UnsolicitedEventListener::popDnsHealthResult() {
    // Wait until the queue is not empty or timeout.
    android::base::Timer t;
    while (t.duration() < milliseconds{1000}) {
        {
            std::lock_guard lock(mMutex);
            if (!mDnsHealthResultRecords.empty()) break;
        }
        std::this_thread::sleep_for(kRetryIntervalMs);
    }

    std::lock_guard lock(mMutex);
    if (mDnsHealthResultRecords.empty()) return Error() << "Dns health result record is empty";

    auto ret = mDnsHealthResultRecords.front();
    mDnsHealthResultRecords.pop();
    return ret;
}

}  // namespace android::net::resolv::aidl
+10 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <utility>

#include <aidl/android/net/resolv/aidl/BnDnsResolverUnsolicitedEventListener.h>
#include <android-base/result.h>
#include <android-base/thread_annotations.h>

namespace android::net::resolv::aidl {
@@ -48,6 +49,9 @@ class UnsolicitedEventListener
    bool waitForNat64Prefix(int operation, const std::chrono::milliseconds& timeout)
            EXCLUDES(mMutex);

    // Pop up last receiving dns health result.
    android::base::Result<int> popDnsHealthResult() EXCLUDES(mMutex);

    // Return true if a validation result for |serverAddr| is found; otherwise, return false.
    bool findValidationRecord(const std::string& serverAddr) const EXCLUDES(mMutex) {
        std::lock_guard lock(mMutex);
@@ -64,6 +68,9 @@ class UnsolicitedEventListener
        std::lock_guard lock(mMutex);
        mValidationRecords.clear();
        mUnexpectedNat64PrefixUpdates = 0;

        std::queue<int> emptyQueue;
        std::swap(mDnsHealthResultRecords, emptyQueue);
    }

  private:
@@ -89,6 +96,9 @@ class UnsolicitedEventListener
    // resort to timeouts that make the tests slower and flakier.
    int mUnexpectedNat64PrefixUpdates GUARDED_BY(mMutex);

    // Used to store the dns health result from onDnsHealthEvent().
    std::queue<int> mDnsHealthResultRecords GUARDED_BY(mMutex);

    mutable std::mutex mMutex;
    std::condition_variable mCv;
};