blob: 4977c63083b8b70fa6b584616ee333bd8c78462c [file] [log] [blame]
/*
* 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 <BinderRpcTestClientInfo.h>
#include <BinderRpcTestServerInfo.h>
#include <BnBinderRpcCallback.h>
#include <BnBinderRpcSession.h>
#include <BnBinderRpcTest.h>
#include <aidl/IBinderRpcTest.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
#include <binder/RpcTlsTestUtils.h>
#include <binder/RpcTlsUtils.h>
#include <binder/RpcTransport.h>
#include <binder/RpcTransportRaw.h>
#include <binder/RpcTransportTls.h>
#include <gtest/gtest.h>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <type_traits>
#include <poll.h>
#include <sys/prctl.h>
#include <unistd.h>
#include "../FdTrigger.h"
#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
using namespace std::chrono_literals;
using namespace std::placeholders;
using testing::AssertionFailure;
using testing::AssertionResult;
using testing::AssertionSuccess;
namespace android {
static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
const char* kLocalInetAddress = "127.0.0.1";
enum class RpcSecurity { RAW, TLS };
static inline std::vector<RpcSecurity> RpcSecurityValues() {
return {RpcSecurity::RAW, RpcSecurity::TLS};
}
static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
std::unique_ptr<RpcAuth> auth = nullptr) {
switch (rpcSecurity) {
case RpcSecurity::RAW:
return RpcTransportCtxFactoryRaw::make();
case RpcSecurity::TLS: {
if (verifier == nullptr) {
verifier = std::make_shared<RpcCertificateVerifierSimple>();
}
if (auth == nullptr) {
auth = std::make_unique<RpcAuthSelfSigned>();
}
return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
}
default:
LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
}
}
TEST(BinderRpcParcel, EntireParcelFormatted) {
Parcel p;
p.writeInt32(3);
EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
}
class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
public:
static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
return newFactory(info.param)->toCString();
}
};
TEST_P(BinderRpcSimple, SetExternalServerTest) {
base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
int sinkFd = sink.get();
auto server = RpcServer::make(newFactory(GetParam()));
ASSERT_FALSE(server->hasServer());
ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
ASSERT_TRUE(server->hasServer());
base::unique_fd retrieved = server->releaseServer();
ASSERT_FALSE(server->hasServer());
ASSERT_EQ(sinkFd, retrieved.get());
}
TEST(BinderRpc, CannotUseNextWireVersion) {
auto session = RpcSession::make();
EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
}
TEST(BinderRpc, CanUseExperimentalWireVersion) {
auto session = RpcSession::make();
EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
}
using android::binder::Status;
#define EXPECT_OK(status) \
do { \
Status stat = (status); \
EXPECT_TRUE(stat.isOk()) << stat; \
} while (false)
class MyBinderRpcSession : public BnBinderRpcSession {
public:
static std::atomic<int32_t> gNum;
MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
Status getName(std::string* name) override {
*name = mName;
return Status::ok();
}
~MyBinderRpcSession() { gNum--; }
private:
std::string mName;
};
std::atomic<int32_t> MyBinderRpcSession::gNum;
class MyBinderRpcCallback : public BnBinderRpcCallback {
Status sendCallback(const std::string& value) {
std::unique_lock _l(mMutex);
mValues.push_back(value);
_l.unlock();
mCv.notify_one();
return Status::ok();
}
Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
public:
std::mutex mMutex;
std::condition_variable mCv;
std::vector<std::string> mValues;
};
class MyBinderRpcTest : public BnBinderRpcTest {
public:
wp<RpcServer> server;
int port = 0;
Status sendString(const std::string& str) override {
(void)str;
return Status::ok();
}
Status doubleString(const std::string& str, std::string* strstr) override {
*strstr = str + str;
return Status::ok();
}
Status getClientPort(int* out) override {
*out = port;
return Status::ok();
}
Status countBinders(std::vector<int32_t>* out) override {
sp<RpcServer> spServer = server.promote();
if (spServer == nullptr) {
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
out->clear();
for (auto session : spServer->listSessions()) {
size_t count = session->state()->countBinders();
out->push_back(count);
}
return Status::ok();
}
Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
if (binder == nullptr) {
std::cout << "Received null binder!" << std::endl;
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
*out = binder->pingBinder();
return Status::ok();
}
Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
*out = binder;
return Status::ok();
}
static sp<IBinder> mHeldBinder;
Status holdBinder(const sp<IBinder>& binder) override {
mHeldBinder = binder;
return Status::ok();
}
Status getHeldBinder(sp<IBinder>* held) override {
*held = mHeldBinder;
return Status::ok();
}
Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
if (count <= 0) return Status::ok();
return binder->nestMe(this, count - 1);
}
Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
static sp<IBinder> binder = new BBinder;
*out = binder;
return Status::ok();
}
Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
*out = new MyBinderRpcSession(name);
return Status::ok();
}
Status getNumOpenSessions(int32_t* out) override {
*out = MyBinderRpcSession::gNum;
return Status::ok();
}
std::mutex blockMutex;
Status lock() override {
blockMutex.lock();
return Status::ok();
}
Status unlockInMsAsync(int32_t ms) override {
usleep(ms * 1000);
blockMutex.unlock();
return Status::ok();
}
Status lockUnlock() override {
std::lock_guard<std::mutex> _l(blockMutex);
return Status::ok();
}
Status sleepMs(int32_t ms) override {
usleep(ms * 1000);
return Status::ok();
}
Status sleepMsAsync(int32_t ms) override {
// In-process binder calls are asynchronous, but the call to this method
// is synchronous wrt its client. This in/out-process threading model
// diffentiation is a classic binder leaky abstraction (for better or
// worse) and is preserved here the way binder sockets plugs itself
// into BpBinder, as nothing is changed at the higher levels
// (IInterface) which result in this behavior.
return sleepMs(ms);
}
Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
const std::string& value) override {
if (callback == nullptr) {
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
if (delayed) {
std::thread([=]() {
ALOGE("Executing delayed callback: '%s'", value.c_str());
Status status = doCallback(callback, oneway, false, value);
ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
}).detach();
return Status::ok();
}
if (oneway) {
return callback->sendOnewayCallback(value);
}
return callback->sendCallback(value);
}
Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
const std::string& value) override {
return doCallback(callback, oneway, delayed, value);
}
Status die(bool cleanup) override {
if (cleanup) {
exit(1);
} else {
_exit(1);
}
}
Status scheduleShutdown() override {
sp<RpcServer> strongServer = server.promote();
if (strongServer == nullptr) {
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
std::thread([=] {
LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
}).detach();
return Status::ok();
}
Status useKernelBinderCallingId() override {
// this is WRONG! It does not make sense when using RPC binder, and
// because it is SO wrong, and so much code calls this, it should abort!
(void)IPCThreadState::self()->getCallingPid();
return Status::ok();
}
};
sp<IBinder> MyBinderRpcTest::mHeldBinder;
class Process {
public:
Process(Process&&) = default;
Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
android::base::borrowed_fd /* readEnd */)>& f) {
android::base::unique_fd childWriteEnd;
android::base::unique_fd childReadEnd;
CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
if (0 == (mPid = fork())) {
// racey: assume parent doesn't crash before this is set
prctl(PR_SET_PDEATHSIG, SIGHUP);
f(childWriteEnd, childReadEnd);
exit(0);
}
}
~Process() {
if (mPid != 0) {
waitpid(mPid, nullptr, 0);
}
}
android::base::borrowed_fd readEnd() { return mReadEnd; }
android::base::borrowed_fd writeEnd() { return mWriteEnd; }
private:
pid_t mPid = 0;
android::base::unique_fd mReadEnd;
android::base::unique_fd mWriteEnd;
};
static std::string allocateSocketAddress() {
static size_t id = 0;
std::string temp = getenv("TMPDIR") ?: "/tmp";
auto ret = temp + "/binderRpcTest_" + std::to_string(id++);
unlink(ret.c_str());
return ret;
};
static unsigned int allocateVsockPort() {
static unsigned int vsockPort = 3456;
return vsockPort++;
}
struct ProcessSession {
// reference to process hosting a socket server
Process host;
struct SessionInfo {
sp<RpcSession> session;
sp<IBinder> root;
};
// client session objects associated with other process
// each one represents a separate session
std::vector<SessionInfo> sessions;
ProcessSession(ProcessSession&&) = default;
~ProcessSession() {
for (auto& session : sessions) {
session.root = nullptr;
}
for (auto& info : sessions) {
sp<RpcSession>& session = info.session;
EXPECT_NE(nullptr, session);
EXPECT_NE(nullptr, session->state());
EXPECT_EQ(0, session->state()->countBinders()) << (session->state()->dump(), "dump:");
wp<RpcSession> weakSession = session;
session = nullptr;
EXPECT_EQ(nullptr, weakSession.promote()) << "Leaked session";
}
}
};
// Process session where the process hosts IBinderRpcTest, the server used
// for most testing here
struct BinderRpcTestProcessSession {
ProcessSession proc;
// pre-fetched root object (for first session)
sp<IBinder> rootBinder;
// pre-casted root object (for first session)
sp<IBinderRpcTest> rootIface;
// whether session should be invalidated by end of run
bool expectAlreadyShutdown = false;
BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
~BinderRpcTestProcessSession() {
EXPECT_NE(nullptr, rootIface);
if (rootIface == nullptr) return;
if (!expectAlreadyShutdown) {
std::vector<int32_t> remoteCounts;
// calling over any sessions counts across all sessions
EXPECT_OK(rootIface->countBinders(&remoteCounts));
EXPECT_EQ(remoteCounts.size(), proc.sessions.size());
for (auto remoteCount : remoteCounts) {
EXPECT_EQ(remoteCount, 1);
}
// even though it is on another thread, shutdown races with
// the transaction reply being written
if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
}
}
rootIface = nullptr;
rootBinder = nullptr;
}
};
enum class SocketType {
PRECONNECTED,
UNIX,
VSOCK,
INET,
};
static inline std::string PrintToString(SocketType socketType) {
switch (socketType) {
case SocketType::PRECONNECTED:
return "preconnected_uds";
case SocketType::UNIX:
return "unix_domain_socket";
case SocketType::VSOCK:
return "vm_socket";
case SocketType::INET:
return "inet_socket";
default:
LOG_ALWAYS_FATAL("Unknown socket type");
return "";
}
}
static base::unique_fd connectTo(const RpcSocketAddress& addr) {
base::unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
int savedErrno = errno;
CHECK(serverFd.ok()) << "Could not create socket " << addr.toString() << ": "
<< strerror(savedErrno);
if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
int savedErrno = errno;
LOG(FATAL) << "Could not connect to socket " << addr.toString() << ": "
<< strerror(savedErrno);
}
return serverFd;
}
class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
public:
struct Options {
size_t numThreads = 1;
size_t numSessions = 1;
size_t numIncomingConnections = 0;
size_t numOutgoingConnections = SIZE_MAX;
};
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
auto [type, security] = info.param;
return PrintToString(type) + "_" + newFactory(security)->toCString();
}
static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
uint64_t length = str.length();
CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
CHECK(android::base::WriteFully(fd, str.data(), str.length()));
}
static inline std::string readString(android::base::borrowed_fd fd) {
uint64_t length;
CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
std::string ret(length, '\0');
CHECK(android::base::ReadFully(fd, ret.data(), length));
return ret;
}
static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
Parcel parcel;
CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
writeString(fd,
std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
}
template <typename T>
static inline T readFromFd(android::base::borrowed_fd fd) {
std::string data = readString(fd);
Parcel parcel;
CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
T object;
CHECK_EQ(OK, object.readFromParcel(&parcel));
return object;
}
// This creates a new process serving an interface on a certain number of
// threads.
ProcessSession createRpcTestSocketServerProcess(
const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
SocketType socketType = std::get<0>(GetParam());
RpcSecurity rpcSecurity = std::get<1>(GetParam());
unsigned int vsockPort = allocateVsockPort();
std::string addr = allocateSocketAddress();
auto ret = ProcessSession{
.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->setMaxThreads(options.numThreads);
unsigned int outPort = 0;
switch (socketType) {
case SocketType::PRECONNECTED:
[[fallthrough]];
case SocketType::UNIX:
CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
break;
case SocketType::VSOCK:
CHECK_EQ(OK, server->setupVsockServer(vsockPort));
break;
case SocketType::INET: {
CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
CHECK_NE(0, outPort);
break;
}
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
BinderRpcTestServerInfo serverInfo;
serverInfo.port = static_cast<int64_t>(outPort);
serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
writeToFd(writeEnd, serverInfo);
auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
if (rpcSecurity == RpcSecurity::TLS) {
for (const auto& clientCert : clientInfo.certs) {
CHECK_EQ(OK,
certVerifier
->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
clientCert.data));
}
}
configure(server);
server->join();
// Another thread calls shutdown. Wait for it to complete.
(void)server->shutdown();
}),
};
std::vector<sp<RpcSession>> sessions;
auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
for (size_t i = 0; i < options.numSessions; i++) {
sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
}
auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
BinderRpcTestClientInfo clientInfo;
for (const auto& session : sessions) {
auto& parcelableCert = clientInfo.certs.emplace_back();
parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
}
writeToFd(ret.host.writeEnd(), clientInfo);
CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
if (socketType == SocketType::INET) {
CHECK_NE(0, serverInfo.port);
}
if (rpcSecurity == RpcSecurity::TLS) {
const auto& serverCert = serverInfo.cert.data;
CHECK_EQ(OK,
certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
serverCert));
}
status_t status;
for (const auto& session : sessions) {
session->setMaxIncomingThreads(options.numIncomingConnections);
session->setMaxOutgoingThreads(options.numOutgoingConnections);
switch (socketType) {
case SocketType::PRECONNECTED:
status = session->setupPreconnectedClient({}, [=]() {
return connectTo(UnixSocketAddress(addr.c_str()));
});
break;
case SocketType::UNIX:
status = session->setupUnixDomainClient(addr.c_str());
break;
case SocketType::VSOCK:
status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
break;
case SocketType::INET:
status = session->setupInetClient("127.0.0.1", serverInfo.port);
break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
ret.sessions.push_back({session, session->getRootObject()});
}
return ret;
}
BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
BinderRpcTestProcessSession ret{
.proc = createRpcTestSocketServerProcess(
options,
[&](const sp<RpcServer>& server) {
server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
// UNIX sockets with abstract addresses return
// sizeof(sa_family_t)==2 in addrlen
CHECK_GE(len, sizeof(sa_family_t));
const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
switch (addr->sa_family) {
case AF_UNIX:
// nothing to save
break;
case AF_VSOCK:
CHECK_EQ(len, sizeof(sockaddr_vm));
service->port = reinterpret_cast<const sockaddr_vm*>(addr)
->svm_port;
break;
case AF_INET:
CHECK_EQ(len, sizeof(sockaddr_in));
service->port =
ntohs(reinterpret_cast<const sockaddr_in*>(addr)
->sin_port);
break;
case AF_INET6:
CHECK_EQ(len, sizeof(sockaddr_in));
service->port =
ntohs(reinterpret_cast<const sockaddr_in6*>(addr)
->sin6_port);
break;
default:
LOG_ALWAYS_FATAL("Unrecognized address family %d",
addr->sa_family);
}
service->server = server;
return service;
});
}),
};
ret.rootBinder = ret.proc.sessions.at(0).root;
ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
return ret;
}
void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
size_t sleepMs = 500);
};
TEST_P(BinderRpc, Ping) {
auto proc = createRpcTestSocketServerProcess({});
ASSERT_NE(proc.rootBinder, nullptr);
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
}
TEST_P(BinderRpc, GetInterfaceDescriptor) {
auto proc = createRpcTestSocketServerProcess({});
ASSERT_NE(proc.rootBinder, nullptr);
EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
}
TEST_P(BinderRpc, MultipleSessions) {
auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
for (auto session : proc.proc.sessions) {
ASSERT_NE(nullptr, session.root);
EXPECT_EQ(OK, session.root->pingBinder());
}
}
TEST_P(BinderRpc, SeparateRootObject) {
SocketType type = std::get<0>(GetParam());
if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
// we can't get port numbers for unix sockets
return;
}
auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
int port1 = 0;
EXPECT_OK(proc.rootIface->getClientPort(&port1));
sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
int port2;
EXPECT_OK(rootIface2->getClientPort(&port2));
// we should have a different IBinderRpcTest object created for each
// session, because we use setPerSessionRootObject
EXPECT_NE(port1, port2);
}
TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
auto proc = createRpcTestSocketServerProcess({});
Parcel data;
Parcel reply;
EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
}
TEST_P(BinderRpc, AppendSeparateFormats) {
auto proc1 = createRpcTestSocketServerProcess({});
auto proc2 = createRpcTestSocketServerProcess({});
Parcel pRaw;
Parcel p1;
p1.markForBinder(proc1.rootBinder);
p1.writeInt32(3);
EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
Parcel p2;
p2.markForBinder(proc2.rootBinder);
p2.writeInt32(7);
EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
}
TEST_P(BinderRpc, UnknownTransaction) {
auto proc = createRpcTestSocketServerProcess({});
Parcel data;
data.markForBinder(proc.rootBinder);
Parcel reply;
EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
}
TEST_P(BinderRpc, SendSomethingOneway) {
auto proc = createRpcTestSocketServerProcess({});
EXPECT_OK(proc.rootIface->sendString("asdf"));
}
TEST_P(BinderRpc, SendAndGetResultBack) {
auto proc = createRpcTestSocketServerProcess({});
std::string doubled;
EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
EXPECT_EQ("cool cool ", doubled);
}
TEST_P(BinderRpc, SendAndGetResultBackBig) {
auto proc = createRpcTestSocketServerProcess({});
std::string single = std::string(1024, 'a');
std::string doubled;
EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
EXPECT_EQ(single + single, doubled);
}
TEST_P(BinderRpc, CallMeBack) {
auto proc = createRpcTestSocketServerProcess({});
int32_t pingResult;
EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
EXPECT_EQ(OK, pingResult);
EXPECT_EQ(0, MyBinderRpcSession::gNum);
}
TEST_P(BinderRpc, RepeatBinder) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> inBinder = new MyBinderRpcSession("foo");
sp<IBinder> outBinder;
EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
EXPECT_EQ(inBinder, outBinder);
wp<IBinder> weak = inBinder;
inBinder = nullptr;
outBinder = nullptr;
// Force reading a reply, to process any pending dec refs from the other
// process (the other process will process dec refs there before processing
// the ping here).
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
EXPECT_EQ(nullptr, weak.promote());
EXPECT_EQ(0, MyBinderRpcSession::gNum);
}
TEST_P(BinderRpc, RepeatTheirBinder) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinderRpcSession> session;
EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
sp<IBinder> inBinder = IInterface::asBinder(session);
sp<IBinder> outBinder;
EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
EXPECT_EQ(inBinder, outBinder);
wp<IBinder> weak = inBinder;
session = nullptr;
inBinder = nullptr;
outBinder = nullptr;
// Force reading a reply, to process any pending dec refs from the other
// process (the other process will process dec refs there before processing
// the ping here).
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
EXPECT_EQ(nullptr, weak.promote());
}
TEST_P(BinderRpc, RepeatBinderNull) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> outBinder;
EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
EXPECT_EQ(nullptr, outBinder);
}
TEST_P(BinderRpc, HoldBinder) {
auto proc = createRpcTestSocketServerProcess({});
IBinder* ptr = nullptr;
{
sp<IBinder> binder = new BBinder();
ptr = binder.get();
EXPECT_OK(proc.rootIface->holdBinder(binder));
}
sp<IBinder> held;
EXPECT_OK(proc.rootIface->getHeldBinder(&held));
EXPECT_EQ(held.get(), ptr);
// stop holding binder, because we test to make sure references are cleaned
// up
EXPECT_OK(proc.rootIface->holdBinder(nullptr));
// and flush ref counts
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
}
// START TESTS FOR LIMITATIONS OF SOCKET BINDER
// These are behavioral differences form regular binder, where certain usecases
// aren't supported.
TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
auto proc1 = createRpcTestSocketServerProcess({});
auto proc2 = createRpcTestSocketServerProcess({});
sp<IBinder> outBinder;
EXPECT_EQ(INVALID_OPERATION,
proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
}
TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
sp<IBinder> outBinder;
EXPECT_EQ(INVALID_OPERATION,
proc.rootIface->repeatBinder(proc.proc.sessions.at(1).root, &outBinder)
.transactionError());
}
TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
sp<IBinder> outBinder;
EXPECT_EQ(INVALID_OPERATION,
proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
}
TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
auto proc = createRpcTestSocketServerProcess({});
// for historical reasons, IServiceManager interface only returns the
// exception code
EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
}
// END TESTS FOR LIMITATIONS OF SOCKET BINDER
TEST_P(BinderRpc, RepeatRootObject) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> outBinder;
EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
EXPECT_EQ(proc.rootBinder, outBinder);
}
TEST_P(BinderRpc, NestedTransactions) {
auto proc = createRpcTestSocketServerProcess({});
auto nastyNester = sp<MyBinderRpcTest>::make();
EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
wp<IBinder> weak = nastyNester;
nastyNester = nullptr;
EXPECT_EQ(nullptr, weak.promote());
}
TEST_P(BinderRpc, SameBinderEquality) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> a;
EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
sp<IBinder> b;
EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
EXPECT_EQ(a, b);
}
TEST_P(BinderRpc, SameBinderEqualityWeak) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> a;
EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
wp<IBinder> weak = a;
a = nullptr;
sp<IBinder> b;
EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
// this is the wrong behavior, since BpBinder
// doesn't implement onIncStrongAttempted
// but make sure there is no crash
EXPECT_EQ(nullptr, weak.promote());
GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
// In order to fix this:
// - need to have incStrongAttempted reflected across IPC boundary (wait for
// response to promote - round trip...)
// - sendOnLastWeakRef, to delete entries out of RpcState table
EXPECT_EQ(b, weak.promote());
}
#define expectSessions(expected, iface) \
do { \
int session; \
EXPECT_OK((iface)->getNumOpenSessions(&session)); \
EXPECT_EQ(expected, session); \
} while (false)
TEST_P(BinderRpc, SingleSession) {
auto proc = createRpcTestSocketServerProcess({});
sp<IBinderRpcSession> session;
EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
std::string out;
EXPECT_OK(session->getName(&out));
EXPECT_EQ("aoeu", out);
expectSessions(1, proc.rootIface);
session = nullptr;
expectSessions(0, proc.rootIface);
}
TEST_P(BinderRpc, ManySessions) {
auto proc = createRpcTestSocketServerProcess({});
std::vector<sp<IBinderRpcSession>> sessions;
for (size_t i = 0; i < 15; i++) {
expectSessions(i, proc.rootIface);
sp<IBinderRpcSession> session;
EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
sessions.push_back(session);
}
expectSessions(sessions.size(), proc.rootIface);
for (size_t i = 0; i < sessions.size(); i++) {
std::string out;
EXPECT_OK(sessions.at(i)->getName(&out));
EXPECT_EQ(std::to_string(i), out);
}
expectSessions(sessions.size(), proc.rootIface);
while (!sessions.empty()) {
sessions.pop_back();
expectSessions(sessions.size(), proc.rootIface);
}
expectSessions(0, proc.rootIface);
}
size_t epochMillis() {
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::seconds;
using std::chrono::system_clock;
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
constexpr size_t kNumThreads = 10;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
EXPECT_OK(proc.rootIface->lock());
// block all but one thread taking locks
std::vector<std::thread> ts;
for (size_t i = 0; i < kNumThreads - 1; i++) {
ts.push_back(std::thread([&] { proc.rootIface->lockUnlock(); }));
}
usleep(100000); // give chance for calls on other threads
// other calls still work
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
constexpr size_t blockTimeMs = 500;
size_t epochMsBefore = epochMillis();
// after this, we should never see a response within this time
EXPECT_OK(proc.rootIface->unlockInMsAsync(blockTimeMs));
// this call should be blocked for blockTimeMs
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
size_t epochMsAfter = epochMillis();
EXPECT_GE(epochMsAfter, epochMsBefore + blockTimeMs) << epochMsBefore;
for (auto& t : ts) t.join();
}
void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
size_t sleepMs) {
size_t epochMsBefore = epochMillis();
std::vector<std::thread> ts;
for (size_t i = 0; i < numCalls; i++) {
ts.push_back(std::thread([&] { iface->sleepMs(sleepMs); }));
}
for (auto& t : ts) t.join();
size_t epochMsAfter = epochMillis();
EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
// Potential flake, but make sure calls are handled in parallel.
EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
}
TEST_P(BinderRpc, ThreadPoolOverSaturated) {
constexpr size_t kNumThreads = 10;
constexpr size_t kNumCalls = kNumThreads + 3;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
}
TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
constexpr size_t kNumThreads = 20;
constexpr size_t kNumOutgoingConnections = 10;
constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
auto proc = createRpcTestSocketServerProcess(
{.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
}
TEST_P(BinderRpc, ThreadingStressTest) {
constexpr size_t kNumClientThreads = 10;
constexpr size_t kNumServerThreads = 10;
constexpr size_t kNumCalls = 100;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumServerThreads});
std::vector<std::thread> threads;
for (size_t i = 0; i < kNumClientThreads; i++) {
threads.push_back(std::thread([&] {
for (size_t j = 0; j < kNumCalls; j++) {
sp<IBinder> out;
EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &out));
EXPECT_EQ(proc.rootBinder, out);
}
}));
}
for (auto& t : threads) t.join();
}
static void saturateThreadPool(size_t threadCount, const sp<IBinderRpcTest>& iface) {
std::vector<std::thread> threads;
for (size_t i = 0; i < threadCount; i++) {
threads.push_back(std::thread([&] { EXPECT_OK(iface->sleepMs(500)); }));
}
for (auto& t : threads) t.join();
}
TEST_P(BinderRpc, OnewayStressTest) {
constexpr size_t kNumClientThreads = 10;
constexpr size_t kNumServerThreads = 10;
constexpr size_t kNumCalls = 1000;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumServerThreads});
std::vector<std::thread> threads;
for (size_t i = 0; i < kNumClientThreads; i++) {
threads.push_back(std::thread([&] {
for (size_t j = 0; j < kNumCalls; j++) {
EXPECT_OK(proc.rootIface->sendString("a"));
}
}));
}
for (auto& t : threads) t.join();
saturateThreadPool(kNumServerThreads, proc.rootIface);
}
TEST_P(BinderRpc, OnewayCallDoesNotWait) {
constexpr size_t kReallyLongTimeMs = 100;
constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
auto proc = createRpcTestSocketServerProcess({});
size_t epochMsBefore = epochMillis();
EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
size_t epochMsAfter = epochMillis();
EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
}
TEST_P(BinderRpc, OnewayCallQueueing) {
constexpr size_t kNumSleeps = 10;
constexpr size_t kNumExtraServerThreads = 4;
constexpr size_t kSleepMs = 50;
// make sure calls to the same object happen on the same thread
auto proc = createRpcTestSocketServerProcess({.numThreads = 1 + kNumExtraServerThreads});
EXPECT_OK(proc.rootIface->lock());
size_t epochMsBefore = epochMillis();
// all these *Async commands should be queued on the server sequentially,
// even though there are multiple threads.
for (size_t i = 0; i + 1 < kNumSleeps; i++) {
proc.rootIface->sleepMsAsync(kSleepMs);
}
EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs));
// this can only return once the final async call has unlocked
EXPECT_OK(proc.rootIface->lockUnlock());
size_t epochMsAfter = epochMillis();
EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
}
TEST_P(BinderRpc, OnewayCallExhaustion) {
constexpr size_t kNumClients = 2;
constexpr size_t kTooLongMs = 1000;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumClients, .numSessions = 2});
// Build up oneway calls on the second session to make sure it terminates
// and shuts down. The first session should be unaffected (proc destructor
// checks the first session).
auto iface = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
std::vector<std::thread> threads;
for (size_t i = 0; i < kNumClients; i++) {
// one of these threads will get stuck queueing a transaction once the
// socket fills up, the other will be able to fill up transactions on
// this object
threads.push_back(std::thread([&] {
while (iface->sleepMsAsync(kTooLongMs).isOk()) {
}
}));
}
for (auto& t : threads) t.join();
Status status = iface->sleepMsAsync(kTooLongMs);
EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
// now that it has died, wait for the remote session to shutdown
std::vector<int32_t> remoteCounts;
do {
EXPECT_OK(proc.rootIface->countBinders(&remoteCounts));
} while (remoteCounts.size() == kNumClients);
// the second session should be shutdown in the other process by the time we
// are able to join above (it'll only be hung up once it finishes processing
// any pending commands). We need to erase this session from the record
// here, so that the destructor for our session won't check that this
// session is valid, but we still want it to test the other session.
proc.proc.sessions.erase(proc.proc.sessions.begin() + 1);
}
TEST_P(BinderRpc, Callbacks) {
const static std::string kTestString = "good afternoon!";
for (bool callIsOneway : {true, false}) {
for (bool callbackIsOneway : {true, false}) {
for (bool delayed : {true, false}) {
auto proc = createRpcTestSocketServerProcess(
{.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
auto cb = sp<MyBinderRpcCallback>::make();
if (callIsOneway) {
EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
kTestString));
} else {
EXPECT_OK(
proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
}
// if both transactions are synchronous and the response is sent back on the
// same thread, everything should have happened in a nested call. Otherwise,
// the callback will be processed on another thread.
if (callIsOneway || callbackIsOneway || delayed) {
using std::literals::chrono_literals::operator""s;
std::unique_lock<std::mutex> _l(cb->mMutex);
cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
}
EXPECT_EQ(cb->mValues.size(), 1)
<< "callIsOneway: " << callIsOneway
<< " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
if (cb->mValues.empty()) continue;
EXPECT_EQ(cb->mValues.at(0), kTestString)
<< "callIsOneway: " << callIsOneway
<< " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
// since we are severing the connection, we need to go ahead and
// tell the server to shutdown and exit so that waitpid won't hang
if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
}
// since this session has an incoming connection w/ a threadpool, we
// need to manually shut it down
EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
proc.expectAlreadyShutdown = true;
}
}
}
}
TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
auto proc = createRpcTestSocketServerProcess({});
auto cb = sp<MyBinderRpcCallback>::make();
Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
EXPECT_EQ(WOULD_BLOCK, status.transactionError());
}
TEST_P(BinderRpc, Die) {
for (bool doDeathCleanup : {true, false}) {
auto proc = createRpcTestSocketServerProcess({});
// make sure there is some state during crash
// 1. we hold their binder
sp<IBinderRpcSession> session;
EXPECT_OK(proc.rootIface->openSession("happy", &session));
// 2. they hold our binder
sp<IBinder> binder = new BBinder();
EXPECT_OK(proc.rootIface->holdBinder(binder));
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
<< "Do death cleanup: " << doDeathCleanup;
proc.expectAlreadyShutdown = true;
}
}
TEST_P(BinderRpc, UseKernelBinderCallingId) {
bool okToFork = ProcessState::selfOrNull() == nullptr;
auto proc = createRpcTestSocketServerProcess({});
// If this process has used ProcessState already, then the forked process
// cannot use it at all. If this process hasn't used it (depending on the
// order tests are run), then the forked process can use it, and we'll only
// catch the invalid usage the second time. Such is the burden of global
// state!
if (okToFork) {
// we can't allocate IPCThreadState so actually the first time should
// succeed :(
EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
}
// second time! we catch the error :)
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
proc.expectAlreadyShutdown = true;
}
TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
auto proc = createRpcTestSocketServerProcess({});
ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
ASSERT_NE(binder, nullptr);
ASSERT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}
TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
auto proc = createRpcTestSocketServerProcess({});
ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
ASSERT_NE(binder, nullptr);
auto ndkBinder = aidl::IBinderRpcTest::fromBinder(binder);
ASSERT_NE(ndkBinder, nullptr);
std::string out;
ndk::ScopedAStatus status = ndkBinder->doubleString("aoeu", &out);
ASSERT_TRUE(status.isOk()) << status.getDescription();
ASSERT_EQ("aoeuaoeu", out);
}
ssize_t countFds() {
DIR* dir = opendir("/proc/self/fd/");
if (dir == nullptr) return -1;
ssize_t ret = 0;
dirent* ent;
while ((ent = readdir(dir)) != nullptr) ret++;
closedir(dir);
return ret;
}
TEST_P(BinderRpc, Fds) {
ssize_t beforeFds = countFds();
ASSERT_GE(beforeFds, 0);
{
auto proc = createRpcTestSocketServerProcess({.numThreads = 10});
ASSERT_EQ(OK, proc.rootBinder->pingBinder());
}
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
TEST_P(BinderRpc, AidlDelegatorTest) {
auto proc = createRpcTestSocketServerProcess({});
auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
ASSERT_NE(nullptr, myDelegator);
std::string doubled;
EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
EXPECT_EQ("cool cool ", doubled);
}
static bool testSupportVsockLoopback() {
// We don't need to enable TLS to know if vsock is supported.
unsigned int vsockPort = allocateVsockPort();
sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
if (status == -EAFNOSUPPORT) {
return false;
}
LOG_ALWAYS_FATAL("Could not setup vsock server: %s", statusToString(status).c_str());
}
server->start();
sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
while (!server->shutdown()) usleep(10000);
ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
return status == OK;
}
static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
static bool hasVsockLoopback = testSupportVsockLoopback();
if (hasVsockLoopback) {
ret.push_back(SocketType::VSOCK);
}
return ret;
}
INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
::testing::Combine(::testing::ValuesIn(testSocketTypes()),
::testing::ValuesIn(RpcSecurityValues())),
BinderRpc::PrintParamInfo);
class BinderRpcServerRootObject
: public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
TEST_P(BinderRpcServerRootObject, WeakRootObject) {
using SetFn = std::function<void(RpcServer*, sp<IBinder>)>;
auto setRootObject = [](bool isStrong) -> SetFn {
return isStrong ? SetFn(&RpcServer::setRootObject) : SetFn(&RpcServer::setRootObjectWeak);
};
auto [isStrong1, isStrong2, rpcSecurity] = GetParam();
auto server = RpcServer::make(newFactory(rpcSecurity));
auto binder1 = sp<BBinder>::make();
IBinder* binderRaw1 = binder1.get();
setRootObject(isStrong1)(server.get(), binder1);
EXPECT_EQ(binderRaw1, server->getRootObject());
binder1.clear();
EXPECT_EQ((isStrong1 ? binderRaw1 : nullptr), server->getRootObject());
auto binder2 = sp<BBinder>::make();
IBinder* binderRaw2 = binder2.get();
setRootObject(isStrong2)(server.get(), binder2);
EXPECT_EQ(binderRaw2, server->getRootObject());
binder2.clear();
EXPECT_EQ((isStrong2 ? binderRaw2 : nullptr), server->getRootObject());
}
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
::testing::Combine(::testing::Bool(), ::testing::Bool(),
::testing::ValuesIn(RpcSecurityValues())));
class OneOffSignal {
public:
// If notify() was previously called, or is called within |duration|, return true; else false.
template <typename R, typename P>
bool wait(std::chrono::duration<R, P> duration) {
std::unique_lock<std::mutex> lock(mMutex);
return mCv.wait_for(lock, duration, [this] { return mValue; });
}
void notify() {
std::unique_lock<std::mutex> lock(mMutex);
mValue = true;
lock.unlock();
mCv.notify_all();
}
private:
std::mutex mMutex;
std::condition_variable mCv;
bool mValue = false;
};
TEST_P(BinderRpcSimple, Shutdown) {
auto addr = allocateSocketAddress();
auto server = RpcServer::make(newFactory(GetParam()));
ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
auto joinEnds = std::make_shared<OneOffSignal>();
// If things are broken and the thread never stops, don't block other tests. Because the thread
// may run after the test finishes, it must not access the stack memory of the test. Hence,
// shared pointers are passed.
std::thread([server, joinEnds] {
server->join();
joinEnds->notify();
}).detach();
bool shutdown = false;
for (int i = 0; i < 10 && !shutdown; i++) {
usleep(300 * 1000); // 300ms; total 3s
if (server->shutdown()) shutdown = true;
}
ASSERT_TRUE(shutdown) << "server->shutdown() never returns true";
ASSERT_TRUE(joinEnds->wait(2s))
<< "After server->shutdown() returns true, join() did not stop after 2s";
}
TEST(BinderRpc, Java) {
#if !defined(__ANDROID__)
GTEST_SKIP() << "This test is only run on Android. Though it can technically run on host on"
"createRpcDelegateServiceManager() with a device attached, such test belongs "
"to binderHostDeviceTest. Hence, just disable this test on host.";
#endif // !__ANDROID__
sp<IServiceManager> sm = defaultServiceManager();
ASSERT_NE(nullptr, sm);
// Any Java service with non-empty getInterfaceDescriptor() would do.
// Let's pick batteryproperties.
auto binder = sm->checkService(String16("batteryproperties"));
ASSERT_NE(nullptr, binder);
auto descriptor = binder->getInterfaceDescriptor();
ASSERT_GE(descriptor.size(), 0);
ASSERT_EQ(OK, binder->pingBinder());
auto rpcServer = RpcServer::make();
unsigned int port;
ASSERT_EQ(OK, rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
auto socket = rpcServer->releaseServer();
auto keepAlive = sp<BBinder>::make();
auto setRpcClientDebugStatus = binder->setRpcClientDebug(std::move(socket), keepAlive);
if (!android::base::GetBoolProperty("ro.debuggable", false) ||
android::base::GetProperty("ro.build.type", "") == "user") {
ASSERT_EQ(INVALID_OPERATION, setRpcClientDebugStatus)
<< "setRpcClientDebug should return INVALID_OPERATION on non-debuggable or user "
"builds, but get "
<< statusToString(setRpcClientDebugStatus);
GTEST_SKIP();
}
ASSERT_EQ(OK, setRpcClientDebugStatus);
auto rpcSession = RpcSession::make();
ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
auto rpcBinder = rpcSession->getRootObject();
ASSERT_NE(nullptr, rpcBinder);
ASSERT_EQ(OK, rpcBinder->pingBinder());
ASSERT_EQ(descriptor, rpcBinder->getInterfaceDescriptor())
<< "getInterfaceDescriptor should not crash system_server";
ASSERT_EQ(OK, rpcBinder->pingBinder());
}
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
BinderRpcSimple::PrintTestParam);
class RpcTransportTestUtils {
public:
using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
using ConnectToServer = std::function<base::unique_fd()>;
// A server that handles client socket connections.
class Server {
public:
explicit Server() {}
Server(Server&&) = default;
~Server() { shutdownAndWait(); }
[[nodiscard]] AssertionResult setUp(
const Param& param,
std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
auto [socketType, rpcSecurity, certificateFormat] = param;
auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
switch (socketType) {
case SocketType::PRECONNECTED: {
return AssertionFailure() << "Not supported by this test";
} break;
case SocketType::UNIX: {
auto addr = allocateSocketAddress();
auto status = rpcServer->setupUnixDomainServer(addr.c_str());
if (status != OK) {
return AssertionFailure()
<< "setupUnixDomainServer: " << statusToString(status);
}
mConnectToServer = [addr] {
return connectTo(UnixSocketAddress(addr.c_str()));
};
} break;
case SocketType::VSOCK: {
auto port = allocateVsockPort();
auto status = rpcServer->setupVsockServer(port);
if (status != OK) {
return AssertionFailure() << "setupVsockServer: " << statusToString(status);
}
mConnectToServer = [port] {
return connectTo(VsockSocketAddress(VMADDR_CID_LOCAL, port));
};
} break;
case SocketType::INET: {
unsigned int port;
auto status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port);
if (status != OK) {
return AssertionFailure() << "setupInetServer: " << statusToString(status);
}
mConnectToServer = [port] {
const char* addr = kLocalInetAddress;
auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
if (aiStart == nullptr) return base::unique_fd{};
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
auto fd = connectTo(
InetSocketAddress(ai->ai_addr, ai->ai_addrlen, addr, port));
if (fd.ok()) return fd;
}
ALOGE("None of the socket address resolved for %s:%u can be connected",
addr, port);
return base::unique_fd{};
};
}
}
mFd = rpcServer->releaseServer();
if (!mFd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
mCtx = newFactory(rpcSecurity, mCertVerifier, std::move(auth))->newServerCtx();
if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
mSetup = true;
return AssertionSuccess();
}
RpcTransportCtx* getCtx() const { return mCtx.get(); }
std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
return mCertVerifier;
}
ConnectToServer getConnectToServerFn() { return mConnectToServer; }
void start() {
LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
mThread = std::make_unique<std::thread>(&Server::run, this);
}
void run() {
LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
std::vector<std::thread> threads;
while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) {
base::unique_fd acceptedFd(
TEMP_FAILURE_RETRY(accept4(mFd.get(), nullptr, nullptr /*length*/,
SOCK_CLOEXEC | SOCK_NONBLOCK)));
threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd));
}
for (auto& thread : threads) thread.join();
}
void handleOne(android::base::unique_fd acceptedFd) {
ASSERT_TRUE(acceptedFd.ok());
auto serverTransport = mCtx->newTransport(std::move(acceptedFd), mFdTrigger.get());
if (serverTransport == nullptr) return; // handshake failed
ASSERT_TRUE(mPostConnect(serverTransport.get(), mFdTrigger.get()));
}
void shutdownAndWait() {
shutdown();
join();
}
void shutdown() { mFdTrigger->trigger(); }
void setPostConnect(
std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> fn) {
mPostConnect = std::move(fn);
}
private:
std::unique_ptr<std::thread> mThread;
ConnectToServer mConnectToServer;
std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
base::unique_fd mFd;
std::unique_ptr<RpcTransportCtx> mCtx;
std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
std::make_shared<RpcCertificateVerifierSimple>();
bool mSetup = false;
// The function invoked after connection and handshake. By default, it is
// |defaultPostConnect| that sends |kMessage| to the client.
std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> mPostConnect =
Server::defaultPostConnect;
void join() {
if (mThread != nullptr) {
mThread->join();
mThread = nullptr;
}
}
static AssertionResult defaultPostConnect(RpcTransport* serverTransport,
FdTrigger* fdTrigger) {
std::string message(kMessage);
iovec messageIov{message.data(), message.size()};
auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
std::nullopt);
if (status != OK) return AssertionFailure() << statusToString(status);
return AssertionSuccess();
}
};
class Client {
public:
explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
Client(Client&&) = default;
[[nodiscard]] AssertionResult setUp(const Param& param) {
auto [socketType, rpcSecurity, certificateFormat] = param;
mFdTrigger = FdTrigger::make();
mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
return AssertionSuccess();
}
RpcTransportCtx* getCtx() const { return mCtx.get(); }
std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
return mCertVerifier;
}
// connect() and do handshake
bool setUpTransport() {
mFd = mConnectToServer();
if (!mFd.ok()) return AssertionFailure() << "Cannot connect to server";
mClientTransport = mCtx->newTransport(std::move(mFd), mFdTrigger.get());
return mClientTransport != nullptr;
}
AssertionResult readMessage(const std::string& expectedMessage = kMessage) {
LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed");
std::string readMessage(expectedMessage.size(), '\0');
iovec readMessageIov{readMessage.data(), readMessage.size()};
status_t readStatus =
mClientTransport->interruptableReadFully(mFdTrigger.get(), &readMessageIov, 1,
std::nullopt);
if (readStatus != OK) {
return AssertionFailure() << statusToString(readStatus);
}
if (readMessage != expectedMessage) {
return AssertionFailure()
<< "Expected " << expectedMessage << ", actual " << readMessage;
}
return AssertionSuccess();
}
void run(bool handshakeOk = true, bool readOk = true) {
if (!setUpTransport()) {
ASSERT_FALSE(handshakeOk) << "newTransport returns nullptr, but it shouldn't";
return;
}
ASSERT_TRUE(handshakeOk) << "newTransport does not return nullptr, but it should";
ASSERT_EQ(readOk, readMessage());
}
private:
ConnectToServer mConnectToServer;
base::unique_fd mFd;
std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
std::unique_ptr<RpcTransportCtx> mCtx;
std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
std::make_shared<RpcCertificateVerifierSimple>();
std::unique_ptr<RpcTransport> mClientTransport;
};
// Make A trust B.
template <typename A, typename B>
static status_t trust(RpcSecurity rpcSecurity,
std::optional<RpcCertificateFormat> certificateFormat, const A& a,
const B& b) {
if (rpcSecurity != RpcSecurity::TLS) return OK;
LOG_ALWAYS_FATAL_IF(!certificateFormat.has_value());
auto bCert = b->getCtx()->getCertificate(*certificateFormat);
return a->getCertVerifier()->addTrustedPeerCertificate(*certificateFormat, bCert);
}
static constexpr const char* kMessage = "hello";
};
class RpcTransportTest : public testing::TestWithParam<RpcTransportTestUtils::Param> {
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 ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
return ret;
}
static std::vector<ParamType> getRpcTranportTestParams() {
std::vector<ParamType> ret;
for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
for (auto rpcSecurity : RpcSecurityValues()) {
switch (rpcSecurity) {
case RpcSecurity::RAW: {
ret.emplace_back(socketType, rpcSecurity, std::nullopt);
} break;
case RpcSecurity::TLS: {
ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
} break;
}
}
}
return ret;
}
template <typename A, typename B>
status_t trust(const A& a, const B& b) {
auto [socketType, rpcSecurity, certificateFormat] = GetParam();
return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
}
};
TEST_P(RpcTransportTest, GoodCertificate) {
auto server = std::make_unique<Server>();
ASSERT_TRUE(server->setUp(GetParam()));
Client client(server->getConnectToServerFn());
ASSERT_TRUE(client.setUp(GetParam()));
ASSERT_EQ(OK, trust(&client, server));
ASSERT_EQ(OK, trust(server, &client));
server->start();
client.run();
}
TEST_P(RpcTransportTest, MultipleClients) {
auto server = std::make_unique<Server>();
ASSERT_TRUE(server->setUp(GetParam()));
std::vector<Client> clients;
for (int i = 0; i < 2; i++) {
auto& client = clients.emplace_back(server->getConnectToServerFn());
ASSERT_TRUE(client.setUp(GetParam()));
ASSERT_EQ(OK, trust(&client, server));
ASSERT_EQ(OK, trust(server, &client));
}
server->start();
for (auto& client : clients) client.run();
}
TEST_P(RpcTransportTest, UntrustedServer) {
auto [socketType, rpcSecurity, certificateFormat] = GetParam();
auto untrustedServer = std::make_unique<Server>();
ASSERT_TRUE(untrustedServer->setUp(GetParam()));
Client client(untrustedServer->getConnectToServerFn());
ASSERT_TRUE(client.setUp(GetParam()));
ASSERT_EQ(OK, trust(untrustedServer, &client));
untrustedServer->start();
// For TLS, this should reject the certificate. For RAW sockets, it should pass because
// the client can't verify the server's identity.
bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
client.run(handshakeOk);
}
TEST_P(RpcTransportTest, MaliciousServer) {
auto [socketType, rpcSecurity, certificateFormat] = GetParam();
auto validServer = std::make_unique<Server>();
ASSERT_TRUE(validServer->setUp(GetParam()));
auto maliciousServer = std::make_unique<Server>();
ASSERT_TRUE(maliciousServer->setUp(GetParam()));
Client client(maliciousServer->getConnectToServerFn());
ASSERT_TRUE(client.setUp(GetParam()));
ASSERT_EQ(OK, trust(&client, validServer));
ASSERT_EQ(OK, trust(validServer, &client));
ASSERT_EQ(OK, trust(maliciousServer, &client));
maliciousServer->start();
// For TLS, this should reject the certificate. For RAW sockets, it should pass because
// the client can't verify the server's identity.
bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
client.run(handshakeOk);
}
TEST_P(RpcTransportTest, UntrustedClient) {
auto [socketType, rpcSecurity, certificateFormat] = GetParam();
auto server = std::make_unique<Server>();
ASSERT_TRUE(server->setUp(GetParam()));
Client client(server->getConnectToServerFn());
ASSERT_TRUE(client.setUp(GetParam()));
ASSERT_EQ(OK, trust(&client, server));
server->start();
// For TLS, Client should be able to verify server's identity, so client should see
// do_handshake() successfully executed. However, server shouldn't be able to verify client's
// identity and should drop the connection, so client shouldn't be able to read anything.
bool readOk = rpcSecurity != RpcSecurity::TLS;
client.run(true, readOk);
}
TEST_P(RpcTransportTest, MaliciousClient) {
auto [socketType, rpcSecurity, certificateFormat] = GetParam();
auto server = std::make_unique<Server>();
ASSERT_TRUE(server->setUp(GetParam()));
Client validClient(server->getConnectToServerFn());
ASSERT_TRUE(validClient.setUp(GetParam()));
Client maliciousClient(server->getConnectToServerFn());
ASSERT_TRUE(maliciousClient.setUp(GetParam()));
ASSERT_EQ(OK, trust(&validClient, server));
ASSERT_EQ(OK, trust(&maliciousClient, server));
server->start();
// See UntrustedClient.
bool readOk = rpcSecurity != RpcSecurity::TLS;
maliciousClient.run(true, readOk);
}
TEST_P(RpcTransportTest, Trigger) {
std::string msg2 = ", world!";
std::mutex writeMutex;
std::condition_variable writeCv;
bool shouldContinueWriting = false;
auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
std::string message(RpcTransportTestUtils::kMessage);
iovec messageIov{message.data(), message.size()};
auto status =
serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, std::nullopt);
if (status != OK) return AssertionFailure() << statusToString(status);
{
std::unique_lock<std::mutex> lock(writeMutex);
if (!writeCv.wait_for(lock, 3s, [&] { return shouldContinueWriting; })) {
return AssertionFailure() << "write barrier not cleared in time!";
}
}
iovec msg2Iov{msg2.data(), msg2.size()};
status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, std::nullopt);
if (status != DEAD_OBJECT)
return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
"should return DEAD_OBJECT, but it is "
<< statusToString(status);
return AssertionSuccess();
};
auto server = std::make_unique<Server>();
ASSERT_TRUE(server->setUp(GetParam()));
// Set up client
Client client(server->getConnectToServerFn());
ASSERT_TRUE(client.setUp(GetParam()));
// Exchange keys
ASSERT_EQ(OK, trust(&client, server));
ASSERT_EQ(OK, trust(server, &client));
server->setPostConnect(serverPostConnect);
server->start();
// connect() to server and do handshake
ASSERT_TRUE(client.setUpTransport());
// read the first message. This ensures that server has finished handshake and start handling
// client fd. Server thread should pause at writeCv.wait_for().
ASSERT_TRUE(client.readMessage(RpcTransportTestUtils::kMessage));
// Trigger server shutdown after server starts handling client FD. This ensures that the second
// write is on an FdTrigger that has been shut down.
server->shutdown();
// Continues server thread to write the second message.
{
std::lock_guard<std::mutex> lock(writeMutex);
shouldContinueWriting = true;
}
writeCv.notify_all();
// After this line, server thread unblocks and attempts to write the second message, but
// shutdown is triggered, so write should failed with DEAD_OBJECT. See |serverPostConnect|.
// On the client side, second read fails with DEAD_OBJECT
ASSERT_FALSE(client.readMessage(msg2));
}
INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
::testing::ValuesIn(RpcTransportTest::getRpcTranportTestParams()),
RpcTransportTest::PrintParamInfo);
class RpcTransportTlsKeyTest
: public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
public:
template <typename A, typename B>
status_t trust(const A& a, const B& b) {
auto [socketType, certificateFormat, keyFormat] = GetParam();
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;
};
};
TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
auto [socketType, certificateFormat, keyFormat] = GetParam();
std::vector<uint8_t> pkeyData, certData;
{
auto pkey = makeKeyPairForSelfSignedCert();
ASSERT_NE(nullptr, pkey);
auto cert = makeSelfSignedCert(pkey.get(), kCertValidSeconds);
ASSERT_NE(nullptr, cert);
pkeyData = serializeUnencryptedPrivatekey(pkey.get(), keyFormat);
certData = serializeCertificate(cert.get(), certificateFormat);
}
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 server = std::make_unique<RpcTransportTestUtils::Server>();
ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
RpcTransportTestUtils::Client client(server->getConnectToServerFn());
ASSERT_TRUE(client.setUp(utilsParam));
ASSERT_EQ(OK, trust(&client, server));
ASSERT_EQ(OK, trust(server, &client));
server->start();
client.run();
}
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)),
RpcTransportTlsKeyTest::PrintParamInfo);
} // namespace android
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
return RUN_ALL_TESTS();
}