Loading Experiments.cpp +8 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "Experiments.h" #include <android-base/format.h> #include <netdutils/DumpWriter.h> #include <string> Loading Loading @@ -46,21 +47,25 @@ void Experiments::dump(DumpWriter& dw) const { dw.println("Experiments list: "); for (const auto& [key, value] : mFlagsMapInt) { ScopedIndent indentStats(dw); dw.println("%.*s: %d", static_cast<int>(key.length()), key.data(), value); if (value == Experiments::kFlagIntDefault) { dw.println(fmt::format("{}: UNSET", key)); } else { dw.println(fmt::format("{}: {}", key, value)); } } } void Experiments::updateInternal() { std::lock_guard guard(mMutex); for (const auto& key : kExperimentFlagKeyList) { mFlagsMapInt[key] = mGetExperimentFlagIntFunction(key, 0); mFlagsMapInt[key] = mGetExperimentFlagIntFunction(key, Experiments::kFlagIntDefault); } } int Experiments::getFlag(std::string_view key, int defaultValue) const { std::lock_guard guard(mMutex); auto it = mFlagsMapInt.find(key); if (it != mFlagsMapInt.end()) { if (it != mFlagsMapInt.end() && it->second != Experiments::kFlagIntDefault) { return it->second; } return defaultValue; Loading Experiments.h +3 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <climits> #include <mutex> #include <string> #include <string_view> Loading Loading @@ -49,6 +50,8 @@ class Experiments { // (retry_count, retransmission_time_interval, dot_connect_timeout_ms) static constexpr const char* const kExperimentFlagKeyList[] = { "keep_listening_udp", "parallel_lookup", "parallel_lookup_sleep_time"}; // This value is used in updateInternal as the default value if any flags can't be found. static constexpr int kFlagIntDefault = INT_MIN; // For testing. friend class ExperimentsTest; const GetExperimentFlagIntFunction mGetExperimentFlagIntFunction; Loading ExperimentsTest.cpp +30 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,19 @@ class ExperimentsTest : public ::testing::Test { EXPECT_THAT(mExperiments.mFlagsMapInt, ::testing::ContainerEq(sFakeFlagsMapInt)); } void expectFlagsMapIntDefault() { std::lock_guard guard(mExperiments.mMutex); for (const auto& [key, value] : mExperiments.mFlagsMapInt) { EXPECT_EQ(value, Experiments::kFlagIntDefault); } } void expectGetDnsExperimentFlagIntDefault(int value) { for (const auto& key : Experiments::kExperimentFlagKeyList) { EXPECT_EQ(mExperiments.getFlag(key, value), value); } } void expectGetDnsExperimentFlagInt() { std::unordered_map<std::string_view, int> tempMap; for (const auto& key : Experiments::kExperimentFlagKeyList) { Loading @@ -78,6 +91,9 @@ class ExperimentsTest : public ::testing::Test { std::lock_guard guard(mExperiments.mMutex); for (const auto& [key, value] : mExperiments.mFlagsMapInt) { std::string flagDump = fmt::format("{}: {}", key, value); if (value == Experiments::kFlagIntDefault) { flagDump = fmt::format("{}: UNSET", key); } SCOPED_TRACE(flagDump); size_t pos = dumpString.find(flagDump, startPos); EXPECT_NE(pos, std::string::npos); Loading Loading @@ -110,6 +126,17 @@ TEST_F(ExperimentsTest, getDnsExperimentFlagInt) { } } TEST_F(ExperimentsTest, getDnsExperimentFlagIntDefaultValue) { // Clear the map and make mExperiments initialized with our default int value. sFakeFlagsMapInt.clear(); mExperiments.update(); expectFlagsMapIntDefault(); std::vector<int> testValues = {100, 50, 30, 5}; for (int testValue : testValues) { expectGetDnsExperimentFlagIntDefault(testValue); } } TEST_F(ExperimentsTest, dump) { std::vector<int> testValues = {100, 37, 0, 30}; for (int testValue : testValues) { Loading @@ -117,6 +144,9 @@ TEST_F(ExperimentsTest, dump) { mExperiments.update(); expectDumpOutput(); } sFakeFlagsMapInt.clear(); mExperiments.update(); expectDumpOutput(); } } // namespace android::net getaddrinfo.cpp +13 −7 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ #include <sys/un.h> #include <unistd.h> #include <chrono> #include <future> #include <android-base/logging.h> Loading Loading @@ -1607,7 +1608,8 @@ struct QueryResult { NetworkDnsEventReported event; }; QueryResult doQuery(const char* name, res_target* t, res_state res) { QueryResult doQuery(const char* name, res_target* t, res_state res, std::chrono::milliseconds sleepTimeMs) { HEADER* hp = (HEADER*)(void*)t->answer.data(); hp->rcode = NOERROR; // default Loading Loading @@ -1643,7 +1645,7 @@ QueryResult doQuery(const char* name, res_target* t, res_state res) { ResState res_temp = fromResState(*res, &event); int rcode = NOERROR; n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0); n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0, sleepTimeMs); if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { // if the query choked with EDNS0, retry without EDNS0 if ((res_temp.netcontext_flags & Loading Loading @@ -1671,13 +1673,17 @@ QueryResult doQuery(const char* name, res_target* t, res_state res) { static int res_queryN_parallel(const char* name, res_target* target, res_state res, int* herrno) { std::vector<std::future<QueryResult>> results; results.reserve(2); std::chrono::milliseconds sleepTimeMs{}; for (res_target* t = target; t; t = t->next) { results.emplace_back(std::async(std::launch::async, doQuery, name, t, res)); results.emplace_back(std::async(std::launch::async, doQuery, name, t, res, sleepTimeMs)); // Avoiding gateways drop packets if queries are sent too close together int sleepTime = android::net::Experiments::getInstance()->getFlag( // Only needed if we have multiple queries in a row. if (t->next) { int sleepFlag = android::net::Experiments::getInstance()->getFlag( "parallel_lookup_sleep_time", SLEEP_TIME_MS); if (sleepTime > 1000) sleepTime = 1000; if (t->next) usleep(sleepTime * 1000); if (sleepFlag > 1000) sleepFlag = 1000; sleepTimeMs = std::chrono::milliseconds(sleepFlag); } } int ancount = 0; Loading res_send.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -76,6 +76,8 @@ #define LOG_TAG "resolv" #include <chrono> #include <sys/param.h> #include <sys/socket.h> #include <sys/time.h> Loading Loading @@ -115,6 +117,7 @@ #include "stats.pb.h" #include "util.h" using namespace std::chrono_literals; // TODO: use the namespace something like android::netd_resolv for libnetd_resolv using android::base::ErrnoError; using android::base::Result; Loading Loading @@ -408,7 +411,7 @@ static DnsQueryEvent* addDnsQueryEvent(NetworkDnsEventReported* event) { } int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, uint32_t flags) { uint32_t flags, std::chrono::milliseconds sleepTimeMs) { LOG(DEBUG) << __func__; // Should not happen Loading Loading @@ -448,6 +451,11 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int return -ESRCH; } // If parallel_lookup is enabled, it might be required to wait some time to avoid // gateways drop packets if queries are sent too close together if (sleepTimeMs != 0ms) { std::this_thread::sleep_for(sleepTimeMs); } // DoT if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) { bool fallback = false; Loading Loading
Experiments.cpp +8 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "Experiments.h" #include <android-base/format.h> #include <netdutils/DumpWriter.h> #include <string> Loading Loading @@ -46,21 +47,25 @@ void Experiments::dump(DumpWriter& dw) const { dw.println("Experiments list: "); for (const auto& [key, value] : mFlagsMapInt) { ScopedIndent indentStats(dw); dw.println("%.*s: %d", static_cast<int>(key.length()), key.data(), value); if (value == Experiments::kFlagIntDefault) { dw.println(fmt::format("{}: UNSET", key)); } else { dw.println(fmt::format("{}: {}", key, value)); } } } void Experiments::updateInternal() { std::lock_guard guard(mMutex); for (const auto& key : kExperimentFlagKeyList) { mFlagsMapInt[key] = mGetExperimentFlagIntFunction(key, 0); mFlagsMapInt[key] = mGetExperimentFlagIntFunction(key, Experiments::kFlagIntDefault); } } int Experiments::getFlag(std::string_view key, int defaultValue) const { std::lock_guard guard(mMutex); auto it = mFlagsMapInt.find(key); if (it != mFlagsMapInt.end()) { if (it != mFlagsMapInt.end() && it->second != Experiments::kFlagIntDefault) { return it->second; } return defaultValue; Loading
Experiments.h +3 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <climits> #include <mutex> #include <string> #include <string_view> Loading Loading @@ -49,6 +50,8 @@ class Experiments { // (retry_count, retransmission_time_interval, dot_connect_timeout_ms) static constexpr const char* const kExperimentFlagKeyList[] = { "keep_listening_udp", "parallel_lookup", "parallel_lookup_sleep_time"}; // This value is used in updateInternal as the default value if any flags can't be found. static constexpr int kFlagIntDefault = INT_MIN; // For testing. friend class ExperimentsTest; const GetExperimentFlagIntFunction mGetExperimentFlagIntFunction; Loading
ExperimentsTest.cpp +30 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,19 @@ class ExperimentsTest : public ::testing::Test { EXPECT_THAT(mExperiments.mFlagsMapInt, ::testing::ContainerEq(sFakeFlagsMapInt)); } void expectFlagsMapIntDefault() { std::lock_guard guard(mExperiments.mMutex); for (const auto& [key, value] : mExperiments.mFlagsMapInt) { EXPECT_EQ(value, Experiments::kFlagIntDefault); } } void expectGetDnsExperimentFlagIntDefault(int value) { for (const auto& key : Experiments::kExperimentFlagKeyList) { EXPECT_EQ(mExperiments.getFlag(key, value), value); } } void expectGetDnsExperimentFlagInt() { std::unordered_map<std::string_view, int> tempMap; for (const auto& key : Experiments::kExperimentFlagKeyList) { Loading @@ -78,6 +91,9 @@ class ExperimentsTest : public ::testing::Test { std::lock_guard guard(mExperiments.mMutex); for (const auto& [key, value] : mExperiments.mFlagsMapInt) { std::string flagDump = fmt::format("{}: {}", key, value); if (value == Experiments::kFlagIntDefault) { flagDump = fmt::format("{}: UNSET", key); } SCOPED_TRACE(flagDump); size_t pos = dumpString.find(flagDump, startPos); EXPECT_NE(pos, std::string::npos); Loading Loading @@ -110,6 +126,17 @@ TEST_F(ExperimentsTest, getDnsExperimentFlagInt) { } } TEST_F(ExperimentsTest, getDnsExperimentFlagIntDefaultValue) { // Clear the map and make mExperiments initialized with our default int value. sFakeFlagsMapInt.clear(); mExperiments.update(); expectFlagsMapIntDefault(); std::vector<int> testValues = {100, 50, 30, 5}; for (int testValue : testValues) { expectGetDnsExperimentFlagIntDefault(testValue); } } TEST_F(ExperimentsTest, dump) { std::vector<int> testValues = {100, 37, 0, 30}; for (int testValue : testValues) { Loading @@ -117,6 +144,9 @@ TEST_F(ExperimentsTest, dump) { mExperiments.update(); expectDumpOutput(); } sFakeFlagsMapInt.clear(); mExperiments.update(); expectDumpOutput(); } } // namespace android::net
getaddrinfo.cpp +13 −7 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ #include <sys/un.h> #include <unistd.h> #include <chrono> #include <future> #include <android-base/logging.h> Loading Loading @@ -1607,7 +1608,8 @@ struct QueryResult { NetworkDnsEventReported event; }; QueryResult doQuery(const char* name, res_target* t, res_state res) { QueryResult doQuery(const char* name, res_target* t, res_state res, std::chrono::milliseconds sleepTimeMs) { HEADER* hp = (HEADER*)(void*)t->answer.data(); hp->rcode = NOERROR; // default Loading Loading @@ -1643,7 +1645,7 @@ QueryResult doQuery(const char* name, res_target* t, res_state res) { ResState res_temp = fromResState(*res, &event); int rcode = NOERROR; n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0); n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0, sleepTimeMs); if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { // if the query choked with EDNS0, retry without EDNS0 if ((res_temp.netcontext_flags & Loading Loading @@ -1671,13 +1673,17 @@ QueryResult doQuery(const char* name, res_target* t, res_state res) { static int res_queryN_parallel(const char* name, res_target* target, res_state res, int* herrno) { std::vector<std::future<QueryResult>> results; results.reserve(2); std::chrono::milliseconds sleepTimeMs{}; for (res_target* t = target; t; t = t->next) { results.emplace_back(std::async(std::launch::async, doQuery, name, t, res)); results.emplace_back(std::async(std::launch::async, doQuery, name, t, res, sleepTimeMs)); // Avoiding gateways drop packets if queries are sent too close together int sleepTime = android::net::Experiments::getInstance()->getFlag( // Only needed if we have multiple queries in a row. if (t->next) { int sleepFlag = android::net::Experiments::getInstance()->getFlag( "parallel_lookup_sleep_time", SLEEP_TIME_MS); if (sleepTime > 1000) sleepTime = 1000; if (t->next) usleep(sleepTime * 1000); if (sleepFlag > 1000) sleepFlag = 1000; sleepTimeMs = std::chrono::milliseconds(sleepFlag); } } int ancount = 0; Loading
res_send.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -76,6 +76,8 @@ #define LOG_TAG "resolv" #include <chrono> #include <sys/param.h> #include <sys/socket.h> #include <sys/time.h> Loading Loading @@ -115,6 +117,7 @@ #include "stats.pb.h" #include "util.h" using namespace std::chrono_literals; // TODO: use the namespace something like android::netd_resolv for libnetd_resolv using android::base::ErrnoError; using android::base::Result; Loading Loading @@ -408,7 +411,7 @@ static DnsQueryEvent* addDnsQueryEvent(NetworkDnsEventReported* event) { } int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, uint32_t flags) { uint32_t flags, std::chrono::milliseconds sleepTimeMs) { LOG(DEBUG) << __func__; // Should not happen Loading Loading @@ -448,6 +451,11 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int return -ESRCH; } // If parallel_lookup is enabled, it might be required to wait some time to avoid // gateways drop packets if queries are sent too close together if (sleepTimeMs != 0ms) { std::this_thread::sleep_for(sleepTimeMs); } // DoT if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) { bool fallback = false; Loading