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

Commit 7ec56b3e authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "libbinder: Add object offsets to RPC Binder protocol" am: bdaf9ec7

parents 937b7333 bdaf9ec7
Loading
Loading
Loading
Loading
+54 −13
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include "Debug.h"
#include "RpcWireFormat.h"
#include "Utils.h"

#include <random>

@@ -493,8 +494,14 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti
        }
    }

    // objectTable always empty for now. Will be populated from `data` soon.
    std::vector<uint32_t> objectTable;
    Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};

    uint32_t bodySize;
    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireTransaction), data.dataSize(),
                                               &bodySize) ||
                                __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
                                                       &bodySize),
                        "Too much data %zu", data.dataSize());
    RpcWireHeader command{
@@ -507,6 +514,8 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti
            .code = code,
            .flags = flags,
            .asyncNumber = asyncNumber,
            // bodySize didn't overflow => this cast is safe
            .parcelDataSize = static_cast<uint32_t>(data.dataSize()),
    };

    constexpr size_t kWaitMaxUs = 1000000;
@@ -521,6 +530,7 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti
            {&command, sizeof(RpcWireHeader)},
            {&transaction, sizeof(RpcWireTransaction)},
            {const_cast<uint8_t*>(data.data()), data.dataSize()},
            objectTableSpan.toIovec(),
    };
    if (status_t status = rpcSend(connection, session, "transaction", iovs, arraysize(iovs),
                                  [&] {
@@ -585,7 +595,9 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
            return status;
    }

    if (command.bodySize < sizeof(RpcWireReply)) {
    const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());

    if (command.bodySize < rpcReplyWireSize) {
        ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
              sizeof(RpcWireReply), command.bodySize);
        (void)session->shutdownAndWait(false);
@@ -593,11 +605,13 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
    }

    RpcWireReply rpcReply;
    CommandData data(command.bodySize - sizeof(RpcWireReply));
    memset(&rpcReply, 0, sizeof(RpcWireReply)); // zero because of potential short read

    CommandData data(command.bodySize - rpcReplyWireSize);
    if (!data.valid()) return NO_MEMORY;

    iovec iovs[]{
            {&rpcReply, sizeof(RpcWireReply)},
            {&rpcReply, rpcReplyWireSize},
            {data.data(), data.size()},
    };
    if (status_t status = rpcRec(connection, session, "reply body", iovs, arraysize(iovs));
@@ -605,11 +619,15 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
        return status;
    if (rpcReply.status != OK) return rpcReply.status;

    uint8_t* parcelData = data.data();
    size_t parcelDataSize = data.size();
    data.release();
    reply->rpcSetDataReference(session, parcelData, parcelDataSize, cleanup_reply_data);
    Span<const uint8_t> parcelSpan = {data.data(), data.size()};
    if (session->getProtocolVersion().value() >=
        RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
        Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
        LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0, "Non-empty object table not supported yet.");
    }

    data.release();
    reply->rpcSetDataReference(session, parcelSpan.data, parcelSpan.size, cleanup_reply_data);
    return OK;
}

@@ -824,12 +842,22 @@ processTransactInternalTailCall:
    reply.markForRpc(session);

    if (replyStatus == OK) {
        Span<const uint8_t> parcelSpan = {transaction->data,
                                          transactionData.size() -
                                                  offsetof(RpcWireTransaction, data)};
        if (session->getProtocolVersion().value() >=
            RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
            Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
            LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0,
                                "Non-empty object table not supported yet.");
        }

        Parcel data;
        // transaction->data is owned by this function. Parcel borrows this data and
        // only holds onto it for the duration of this function call. Parcel will be
        // deleted before the 'transactionData' object.
        data.rpcSetDataReference(session, transaction->data,
                                 transactionData.size() - offsetof(RpcWireTransaction, data),

        data.rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
                                 do_nothing_to_transact_data);

        if (target) {
@@ -941,8 +969,16 @@ processTransactInternalTailCall:
        replyStatus = flushExcessBinderRefs(session, addr, target);
    }

    const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());

    // objectTable always empty for now. Will be populated from `reply` soon.
    std::vector<uint32_t> objectTable;
    Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};

    uint32_t bodySize;
    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireReply), reply.dataSize(), &bodySize),
    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(rpcReplyWireSize, reply.dataSize(), &bodySize) ||
                                __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
                                                       &bodySize),
                        "Too much data for reply %zu", reply.dataSize());
    RpcWireHeader cmdReply{
            .command = RPC_COMMAND_REPLY,
@@ -950,12 +986,17 @@ processTransactInternalTailCall:
    };
    RpcWireReply rpcReply{
            .status = replyStatus,
            // NOTE: Not necessarily written to socket depending on session
            // version.
            // NOTE: bodySize didn't overflow => this cast is safe
            .parcelDataSize = static_cast<uint32_t>(reply.dataSize()),
            .reserved = {0, 0, 0},
    };

    iovec iovs[]{
            {&cmdReply, sizeof(RpcWireHeader)},
            {&rpcReply, sizeof(RpcWireReply)},
            {&rpcReply, rpcReplyWireSize},
            {const_cast<uint8_t*>(reply.data()), reply.dataSize()},
            objectTableSpan.toIovec(),
    };
    return rpcSend(connection, session, "reply", iovs, arraysize(iovs), std::nullopt);
}
+20 −2
Original line number Diff line number Diff line
@@ -131,7 +131,10 @@ struct RpcWireTransaction {

    uint64_t asyncNumber;

    uint32_t reserved[4];
    // The size of the Parcel data directly following RpcWireTransaction.
    uint32_t parcelDataSize;

    uint32_t reserved[3];

    uint8_t data[];
};
@@ -139,8 +142,23 @@ static_assert(sizeof(RpcWireTransaction) == 40);

struct RpcWireReply {
    int32_t status; // transact return

    // -- Fields below only transmitted starting at protocol version 1 --

    // The size of the Parcel data directly following RpcWireReply.
    uint32_t parcelDataSize;

    uint32_t reserved[3];

    // Byte size of RpcWireReply in the wire protocol.
    static size_t wireSize(uint32_t protocolVersion) {
        if (protocolVersion == 0) {
            return sizeof(int32_t);
        }
        return sizeof(RpcWireReply);
    }
};
static_assert(sizeof(RpcWireReply) == 4);
static_assert(sizeof(RpcWireReply) == 20);

#pragma clang diagnostic pop

+24 −1
Original line number Diff line number Diff line
@@ -14,8 +14,9 @@
 * limitations under the License.
 */

#include <cstdint>
#include <stddef.h>
#include <cstdint>
#include <optional>

#include <android-base/result.h>
#include <android-base/unique_fd.h>
@@ -39,4 +40,26 @@ android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);

status_t getRandomBytes(uint8_t* data, size_t size);

// View of contiguous sequence. Similar to std::span.
template <typename T>
struct Span {
    T* data = nullptr;
    size_t size = 0;

    size_t byteSize() { return size * sizeof(T); }

    iovec toIovec() { return {const_cast<std::remove_const_t<T>*>(data), byteSize()}; }

    // Truncates `this` to a length of `offset` and returns a span with the
    // remainder.
    //
    // Aborts if offset > size.
    Span<T> splitOff(size_t offset) {
        LOG_ALWAYS_FATAL_IF(offset > size);
        Span<T> rest = {data + offset, size - offset};
        size = offset;
        return rest;
    }
};

}   // namespace android
+7 −1
Original line number Diff line number Diff line
@@ -38,7 +38,13 @@ class FdTrigger;

constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = 0;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;

// Starting with this version:
//
// * RpcWireReply is larger (4 bytes -> 20).
// * RpcWireTransaction and RpcWireReplyV1 include the parcel data size.
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE = 1;

/**
 * This represents a session (group of connections) between a client
+84 −42
Original line number Diff line number Diff line
@@ -99,17 +99,19 @@ TEST(BinderRpcParcel, EntireParcelFormatted) {
    EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
}

class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> {
public:
    static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
        return newFactory(info.param)->toCString();
        return std::string(newFactory(std::get<0>(info.param))->toCString()) + "_serverV" +
                std::to_string(std::get<1>(info.param));
    }
};

TEST_P(BinderRpcSimple, SetExternalServerTest) {
TEST_P(BinderRpcServerOnly, SetExternalServerTest) {
    base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
    int sinkFd = sink.get();
    auto server = RpcServer::make(newFactory(GetParam()));
    auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
    server->setProtocolVersion(std::get<1>(GetParam()));
    ASSERT_FALSE(server->hasServer());
    ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
    ASSERT_TRUE(server->hasServer());
@@ -480,7 +482,8 @@ static base::unique_fd connectTo(const RpcSocketAddress& addr) {
    return serverFd;
}

class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
class BinderRpc
      : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t>> {
public:
    struct Options {
        size_t numThreads = 1;
@@ -490,8 +493,9 @@ public:
    };

    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
        auto [type, security] = info.param;
        return PrintToString(type) + "_" + newFactory(security)->toCString();
        auto [type, security, clientVersion, serverVersion] = info.param;
        return PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
                std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
    }

    static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
@@ -533,16 +537,19 @@ public:

        SocketType socketType = std::get<0>(GetParam());
        RpcSecurity rpcSecurity = std::get<1>(GetParam());
        uint32_t clientVersion = std::get<2>(GetParam());
        uint32_t serverVersion = std::get<3>(GetParam());

        unsigned int vsockPort = allocateVsockPort();
        std::string addr = allocateSocketAddress();

        auto ret = ProcessSession{
                .host = Process([&](android::base::borrowed_fd writeEnd,
                .host = Process([=](android::base::borrowed_fd writeEnd,
                                    android::base::borrowed_fd readEnd) {
                    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
                    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));

                    server->setProtocolVersion(serverVersion);
                    server->setMaxThreads(options.numThreads);

                    unsigned int outPort = 0;
@@ -618,6 +625,7 @@ public:
        status_t status;

        for (const auto& session : sessions) {
            CHECK(session->setProtocolVersion(clientVersion));
            session->setMaxIncomingThreads(options.numIncomingConnections);
            session->setMaxOutgoingThreads(options.numOutgoingConnections);

@@ -1420,9 +1428,20 @@ static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
    return ret;
}

static std::vector<uint32_t> testVersions() {
    std::vector<uint32_t> versions;
    for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) {
        versions.push_back(i);
    }
    versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
    return versions;
}

INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
                        ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
                                           ::testing::ValuesIn(RpcSecurityValues())),
                                           ::testing::ValuesIn(RpcSecurityValues()),
                                           ::testing::ValuesIn(testVersions()),
                                           ::testing::ValuesIn(testVersions())),
                        BinderRpc::PrintParamInfo);

class BinderRpcServerRootObject
@@ -1476,9 +1495,10 @@ private:
    bool mValue = false;
};

TEST_P(BinderRpcSimple, Shutdown) {
TEST_P(BinderRpcServerOnly, Shutdown) {
    auto addr = allocateSocketAddress();
    auto server = RpcServer::make(newFactory(GetParam()));
    auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
    server->setProtocolVersion(std::get<1>(GetParam()));
    ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
    auto joinEnds = std::make_shared<OneOffSignal>();

@@ -1548,12 +1568,17 @@ TEST(BinderRpc, Java) {
    ASSERT_EQ(OK, rpcBinder->pingBinder());
}

INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
                        BinderRpcSimple::PrintTestParam);
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerOnly,
                        ::testing::Combine(::testing::ValuesIn(RpcSecurityValues()),
                                           ::testing::ValuesIn(testVersions())),
                        BinderRpcServerOnly::PrintTestParam);

class RpcTransportTestUtils {
public:
    using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
    // Only parameterized only server version because `RpcSession` is bypassed
    // in the client half of the tests.
    using Param =
            std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>, uint32_t>;
    using ConnectToServer = std::function<base::unique_fd()>;

    // A server that handles client socket connections.
@@ -1565,8 +1590,9 @@ public:
        [[nodiscard]] AssertionResult setUp(
                const Param& param,
                std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
            auto [socketType, rpcSecurity, certificateFormat] = param;
            auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
            auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
            rpcServer->setProtocolVersion(serverVersion);
            switch (socketType) {
                case SocketType::PRECONNECTED: {
                    return AssertionFailure() << "Not supported by this test";
@@ -1696,7 +1722,8 @@ public:
        explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
        Client(Client&&) = default;
        [[nodiscard]] AssertionResult setUp(const Param& param) {
            auto [socketType, rpcSecurity, certificateFormat] = param;
            auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
            (void)serverVersion;
            mFdTrigger = FdTrigger::make();
            mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
            if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
@@ -1767,31 +1794,37 @@ public:
    using Server = RpcTransportTestUtils::Server;
    using Client = RpcTransportTestUtils::Client;
    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
        auto [socketType, rpcSecurity, certificateFormat] = info.param;
        auto [socketType, rpcSecurity, certificateFormat, serverVersion] = info.param;
        auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
        if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
        ret += "_serverV" + std::to_string(serverVersion);
        return ret;
    }
    static std::vector<ParamType> getRpcTranportTestParams() {
        std::vector<ParamType> ret;
        for (auto serverVersion : testVersions()) {
            for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
                for (auto rpcSecurity : RpcSecurityValues()) {
                    switch (rpcSecurity) {
                        case RpcSecurity::RAW: {
                        ret.emplace_back(socketType, rpcSecurity, std::nullopt);
                            ret.emplace_back(socketType, rpcSecurity, std::nullopt, serverVersion);
                        } break;
                        case RpcSecurity::TLS: {
                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
                            ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM,
                                             serverVersion);
                            ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER,
                                             serverVersion);
                        } break;
                    }
                }
            }
        }
        return ret;
    }
    template <typename A, typename B>
    status_t trust(const A& a, const B& b) {
        auto [socketType, rpcSecurity, certificateFormat] = GetParam();
        auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
        (void)serverVersion;
        return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
    }
};
@@ -1827,7 +1860,8 @@ TEST_P(RpcTransportTest, MultipleClients) {
}

TEST_P(RpcTransportTest, UntrustedServer) {
    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
    (void)serverVersion;

    auto untrustedServer = std::make_unique<Server>();
    ASSERT_TRUE(untrustedServer->setUp(GetParam()));
@@ -1845,7 +1879,9 @@ TEST_P(RpcTransportTest, UntrustedServer) {
    client.run(handshakeOk);
}
TEST_P(RpcTransportTest, MaliciousServer) {
    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
    (void)serverVersion;

    auto validServer = std::make_unique<Server>();
    ASSERT_TRUE(validServer->setUp(GetParam()));

@@ -1868,7 +1904,9 @@ TEST_P(RpcTransportTest, MaliciousServer) {
}

TEST_P(RpcTransportTest, UntrustedClient) {
    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
    (void)serverVersion;

    auto server = std::make_unique<Server>();
    ASSERT_TRUE(server->setUp(GetParam()));

@@ -1887,7 +1925,9 @@ TEST_P(RpcTransportTest, UntrustedClient) {
}

TEST_P(RpcTransportTest, MaliciousClient) {
    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
    (void)serverVersion;

    auto server = std::make_unique<Server>();
    ASSERT_TRUE(server->setUp(GetParam()));

@@ -1973,23 +2013,24 @@ INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
                        RpcTransportTest::PrintParamInfo);

class RpcTransportTlsKeyTest
      : public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
      : public testing::TestWithParam<
                std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat, uint32_t>> {
public:
    template <typename A, typename B>
    status_t trust(const A& a, const B& b) {
        auto [socketType, certificateFormat, keyFormat] = GetParam();
        auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
        (void)serverVersion;
        return RpcTransportTestUtils::trust(RpcSecurity::TLS, certificateFormat, a, b);
    }
    static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
        auto [socketType, certificateFormat, keyFormat] = info.param;
        auto ret = PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
                "_key_" + PrintToString(keyFormat);
        return ret;
        auto [socketType, certificateFormat, keyFormat, serverVersion] = info.param;
        return PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
                "_key_" + PrintToString(keyFormat) + "_serverV" + std::to_string(serverVersion);
    };
};

TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
    auto [socketType, certificateFormat, keyFormat] = GetParam();
    auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();

    std::vector<uint8_t> pkeyData, certData;
    {
@@ -2004,8 +2045,8 @@ TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
    auto desPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
    auto desCert = deserializeCertificate(certData, certificateFormat);
    auto auth = std::make_unique<RpcAuthPreSigned>(std::move(desPkey), std::move(desCert));
    auto utilsParam =
            std::make_tuple(socketType, RpcSecurity::TLS, std::make_optional(certificateFormat));
    auto utilsParam = std::make_tuple(socketType, RpcSecurity::TLS,
                                      std::make_optional(certificateFormat), serverVersion);

    auto server = std::make_unique<RpcTransportTestUtils::Server>();
    ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
@@ -2024,7 +2065,8 @@ INSTANTIATE_TEST_CASE_P(
        BinderRpc, RpcTransportTlsKeyTest,
        testing::Combine(testing::ValuesIn(testSocketTypes(false /* hasPreconnected*/)),
                         testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER)),
                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
                         testing::ValuesIn(testVersions())),
        RpcTransportTlsKeyTest::PrintParamInfo);

} // namespace android
Loading