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

Commit b6d74c5d authored by Luke Huang's avatar Luke Huang Committed by Gerrit Code Review
Browse files

Merge "Add Experiments to handle experiment flags logic"

parents 4a79e3c3 f40df9cc
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ cc_library {
        "DnsTlsServer.cpp",
        "DnsTlsSessionCache.cpp",
        "DnsTlsSocket.cpp",
        "Experiments.cpp",
        "PrivateDnsConfiguration.cpp",
        "ResolverController.cpp",
        "ResolverEventReporter.cpp",
@@ -246,8 +247,9 @@ cc_test {
        "resolv_callback_unit_test.cpp",
        "resolv_tls_unit_test.cpp",
        "resolv_unit_test.cpp",
        "DnsStatsTest.cpp",
        "DnsQueryLogTest.cpp",
        "DnsStatsTest.cpp",
        "ExperimentsTest.cpp",
    ],
    shared_libs: [
        "libcrypto",
+4 −3
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <private/android_filesystem_config.h>  // AID_SYSTEM

#include "DnsResolver.h"
#include "Experiments.h"
#include "NetdPermissions.h"  // PERM_*
#include "ResolverEventReporter.h"
#include "resolv_cache.h"
@@ -115,7 +116,7 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num
        gDnsResolv->resolverCtrl.dump(dw, netId);
        dw.blankline();
    }

    Experiments::getInstance()->dump(dw);
    return STATUS_OK;
}

@@ -252,7 +253,7 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num
    ENFORCE_NETWORK_STACK_PERMISSIONS();

    gDnsResolv->resolverCtrl.destroyNetworkCache(netId);

    Experiments::getInstance()->update();
    return ::ndk::ScopedAStatus(AStatus_newOk());
}

@@ -261,7 +262,7 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num
    ENFORCE_NETWORK_STACK_PERMISSIONS();

    int res = gDnsResolv->resolverCtrl.createNetworkCache(netId);

    Experiments::getInstance()->update();
    return statusFromErrcode(res);
}

Experiments.cpp

0 → 100644
+69 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2020, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Experiments.h"

#include <netdutils/DumpWriter.h>
#include <string>

#include "util.h"

namespace android::net {

using netdutils::DumpWriter;
using netdutils::ScopedIndent;

Experiments* Experiments::getInstance() {
    // Instantiated on first use.
    static Experiments instance{getExperimentFlagInt};
    return &instance;
}

Experiments::Experiments(GetExperimentFlagIntFunction getExperimentFlagIntFunction)
    : mGetExperimentFlagIntFunction(std::move(getExperimentFlagIntFunction)) {
    updateInternal();
}

void Experiments::update() {
    updateInternal();
}

void Experiments::dump(DumpWriter& dw) const {
    std::lock_guard guard(mMutex);
    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);
    }
}

void Experiments::updateInternal() {
    std::lock_guard guard(mMutex);
    for (const auto& key : kExperimentFlagKeyList) {
        mFlagsMapInt[key] = mGetExperimentFlagIntFunction(key, 0);
    }
}

int Experiments::getFlag(std::string_view key, int defaultValue) const {
    std::lock_guard guard(mMutex);
    auto it = mFlagsMapInt.find(key);
    if (it != mFlagsMapInt.end()) {
        return it->second;
    }
    return defaultValue;
}

}  // namespace android::net

Experiments.h

0 → 100644
+57 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2020, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <mutex>
#include <string>
#include <string_view>
#include <unordered_map>

#include <android-base/thread_annotations.h>
#include <netdutils/DumpWriter.h>

namespace android::net {

// TODO: Add some way to update the stored experiment flags periodically.
// TODO: Refactor this class and make things easier. (e.g. remove string map.)
class Experiments {
  public:
    using GetExperimentFlagIntFunction = std::function<int(const std::string&, int)>;
    static Experiments* getInstance();
    int getFlag(std::string_view key, int defaultValue) const EXCLUDES(mMutex);
    void update();
    void dump(netdutils::DumpWriter& dw) const EXCLUDES(mMutex);

    Experiments(Experiments const&) = delete;
    void operator=(Experiments const&) = delete;

  private:
    explicit Experiments(GetExperimentFlagIntFunction getExperimentFlagIntFunction);
    Experiments() = delete;
    void updateInternal() EXCLUDES(mMutex);
    mutable std::mutex mMutex;
    std::unordered_map<std::string_view, int> mFlagsMapInt GUARDED_BY(mMutex);
    // TODO: Migrate other experiment flags to here.
    // (retry_count, retransmission_time_interval, dot_connect_timeout_ms)
    static constexpr const char* const kExperimentFlagKeyList[] = {
            "keep_listening_udp", "parallel_lookup", "parallel_lookup_sleep_time"};
    // For testing.
    friend class ExperimentsTest;
    const GetExperimentFlagIntFunction mGetExperimentFlagIntFunction;
};

}  // namespace android::net

ExperimentsTest.cpp

0 → 100644
+122 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <mutex>
#include <string>
#include <string_view>
#include <unordered_map>

#include <android-base/format.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "Experiments.h"

namespace android::net {

class ExperimentsTest : public ::testing::Test {
  public:
    ExperimentsTest() : mExperiments(fakeGetExperimentFlagInt) {}

  protected:
    static int fakeGetExperimentFlagInt(const std::string& key, int defaultValue) {
        auto it = sFakeFlagsMapInt.find(key);
        if (it != sFakeFlagsMapInt.end()) {
            return it->second;
        }
        return defaultValue;
    }

    void setupFakeMap(int value) {
        for (const auto& key : Experiments::kExperimentFlagKeyList) {
            sFakeFlagsMapInt[key] = value;
        }
    }

    void setupExperimentsMap(int value) {
        setupFakeMap(value);
        std::lock_guard guard(mExperiments.mMutex);
        mExperiments.mFlagsMapInt = sFakeFlagsMapInt;
    }

    void expectFlagsMapInt() {
        std::lock_guard guard(mExperiments.mMutex);
        EXPECT_THAT(mExperiments.mFlagsMapInt, ::testing::ContainerEq(sFakeFlagsMapInt));
    }

    void expectGetDnsExperimentFlagInt() {
        std::unordered_map<std::string_view, int> tempMap;
        for (const auto& key : Experiments::kExperimentFlagKeyList) {
            tempMap[key] = mExperiments.getFlag(key, 0);
        }
        EXPECT_THAT(tempMap, ::testing::ContainerEq(sFakeFlagsMapInt));
    }

    void expectDumpOutput() {
        netdutils::DumpWriter dw(STDOUT_FILENO);
        CapturedStdout captured;
        mExperiments.dump(dw);
        const std::string dumpString = captured.str();
        const std::string title = "Experiments list:";
        EXPECT_EQ(dumpString.find(title), 0U);
        size_t startPos = title.size();
        std::lock_guard guard(mExperiments.mMutex);
        for (const auto& [key, value] : mExperiments.mFlagsMapInt) {
            std::string flagDump = fmt::format("{}: {}", key, value);
            SCOPED_TRACE(flagDump);
            size_t pos = dumpString.find(flagDump, startPos);
            EXPECT_NE(pos, std::string::npos);
            startPos = pos + flagDump.size();
        }
        EXPECT_EQ(startPos + 1, dumpString.size());
        EXPECT_EQ(dumpString.substr(startPos), "\n");
    }

    static std::unordered_map<std::string_view, int> sFakeFlagsMapInt;
    Experiments mExperiments;
};

std::unordered_map<std::string_view, int> ExperimentsTest::sFakeFlagsMapInt;

TEST_F(ExperimentsTest, update) {
    std::vector<int> testValues = {50, 3, 5, 0};
    for (int testValue : testValues) {
        setupFakeMap(testValue);
        mExperiments.update();
        expectFlagsMapInt();
    }
}

TEST_F(ExperimentsTest, getDnsExperimentFlagInt) {
    std::vector<int> testValues = {5, 1, 6, 0};
    for (int testValue : testValues) {
        setupExperimentsMap(testValue);
        expectGetDnsExperimentFlagInt();
    }
}

TEST_F(ExperimentsTest, dump) {
    std::vector<int> testValues = {100, 37, 0, 30};
    for (int testValue : testValues) {
        setupFakeMap(testValue);
        mExperiments.update();
        expectDumpOutput();
    }
}

}  // namespace android::net
Loading